Coq:哈斯克尔复制函数的强规范



我在理解Coq中强规范和弱规范之间的区别时遇到了一些困难。例如,如果我想用强规范的方式编写复制函数(给定一个数字n和一个值x,它会创建一个长度为n的列表,所有元素都等于x(,我该如何做到这一点?显然,我必须写一篇"归纳";版本";功能,但如何?

Haskell:中的定义

myReplicate :: Int -> a -> [a]
myReplicate 0 _ = []
myReplicate n x | n > 0 = x:myReplicate (n-1) x
| otherwise = []

规范的定义

用弱规范定义这些函数,然后添加伴随引理。例如,我们定义了一个函数f:a->B,我们证明了形式为∀x:a,Rx(fx(的一个声明,其中R是编码函数的预期输入/输出行为的关系。

strong规范的定义

为了给函数一个强有力的规范:这个函数的类型直接声明输入是类型a的值x,输出是类型B的值v和v满足Rxv的证明的组合。这种规范通常依赖于依赖类型。

编辑:我收到了老师的回复,显然我必须做一些类似的事情,但对于复制的情况:

"例如,如果我们想从其规范中提取一个计算列表长度的函数,我们可以定义一个关系RelLength,它建立了预期输入和输出之间的关系,然后证明它

Inductive RelLength (A:Type) : nat -> list A -> Prop :=
| len_nil : RelLength  0 nil
| len_cons : forall l x n, RelLength n l -> RelLength (S n) (x::l) .

Theorem len_corr : forall (A:Type) (l:list A),  {n | RelLength n l}.
Proof.
…
Qed.
Recursive Extraction len_corr.

用于证明的函数必须直接使用列表"recursor"(这就是fixpoint不会显示的原因——它隐藏在list_rect中(。

所以你不需要写函数本身,只需要写关系,因为函数将由证明定义">

知道了这一点,我该如何将其应用于复制功能案例?

只是为了好玩,下面是Haskell中的样子,在那里依赖一切的ish要烦人得多。这段代码使用了一些非常新的GHC功能,主要是为了使类型更加明确,但可以很容易地进行修改,以便与旧的GHC版本一起使用。

{-# language GADTs, TypeFamilies, PolyKinds, DataKinds, ScopedTypeVariables,
TypeOperators, TypeApplications, StandaloneKindSignatures #-}
{-# OPTIONS_GHC -Wincomplete-patterns #-}
module RelRepl where
import Data.Kind (Type)
import Data.Type.Equality ((:~:)(..))
-- | Singletons (borrowed from the `singletons` package).
type Sing :: forall (k :: Type). k -> Type
type family Sing
type instance Sing @Nat = SNat
type instance Sing @[a] = SList @a
-- The version of Sing in the singletons package has many more instances;
-- in any case, more can be added anywhere as needed.
-- Natural numbers, used at the type level
data Nat = Z | S Nat
-- Singleton representations of natural numbers, used
-- at the term level.
data SNat :: Nat -> Type where
SZ :: SNat 'Z
SS :: SNat n -> SNat ('S n)
-- Singleton lists
data SList :: forall (a :: Type). [a] -> Type where
SNil :: SList '[]
SCons :: Sing a -> SList as -> SList (a ': as)
-- The relation representing the `replicate` function.
data RelRepl :: forall (a :: Type). Nat -> a -> [a] -> Type where
Repl_Z :: forall x. RelRepl 'Z x '[]
Repl_S :: forall n x l. RelRepl n x l -> RelRepl ('S n) x (x ': l)
-- Dependent pairs, because those aren't natively supported.
data DPair :: forall (a :: Type). (a -> Type) -> Type where
MkDPair :: forall {a :: Type} (x :: a) (p :: a -> Type).
Sing x -> p x -> DPair @a p
-- Proof that every natural number and value produce a list
-- satisfying the relation.
repl_corr :: forall {a :: Type} (n :: Nat) (x :: a).
SNat n -> Sing x -> DPair @[a] (RelRepl n x)
repl_corr SZ _x = MkDPair SNil Repl_Z
repl_corr (SS n) x
| MkDPair l pf <- repl_corr n x
= MkDPair (SCons x l) (Repl_S pf)
-- Here's a proof that the relation indeed specifies
-- a *unique* function.
replUnique :: forall {a :: Type} (n :: Nat) (x :: a) (xs :: [a]) (ys :: [a]).
RelRepl n x xs -> RelRepl n x ys -> xs :~: ys
replUnique Repl_Z Repl_Z = Refl
replUnique (Repl_S pf1) (Repl_S pf2)
| Refl <- replUnique pf1 pf2
= Refl 

可能的规范如下所示:

Inductive RelReplicate (A : Type) (a : A) : nat -> (list A) -> Prop :=
| rep0 : RelReplicate A a 0 nil
| repS : …

我做了零的案子,留给你后续的案子。它的结论应该类似于RelReplicate A a (S n) (a :: l)。在你的例子中,你可以试着证明

Theorem replicate_corr : forall (A:Type) (a : A) (n : nat), {l | ReplicateRel A a n l}.

这通过在CCD_ 2上的诱导应该是容易的。如果你想检查你的函数replicate_corr是否符合你的想法,你可以用在几个例子上试试

Eval compute in (proj1_sig (rep_corr nat 0 3)).

其评估rep_corr的第一个自变量(对应于"实函数"而不是证明的自变量(。要做到这一点,您应该用Defined而不是Qed结束Theorem,以便Coq可以对其进行评估。

最新更新