考虑map
的定义:
Fixpoint map (xs: list nat): (nat -> nat) -> list nat := match xs with
| nil => fun _ => nil
| x::xs' => fun f => (f x) :: (map xs' f)
end.
它是这样的:
Coq < Eval simpl in map (1::2::3::List.nil) (fun x => x + 1).
= 2 :: 3 :: 4 :: nil
: list nat
如何扩展它以适用于任何类型?
例如,在Haskell中,我可以简单地编写如下:
map :: forall a b. [a] -> (a -> b) -> [b]
map xs = case xs of
[ ] -> \_ -> [ ]
(x:xs') -> \f -> f x: map xs' f
但是在Coq中,我不知道该forall
量词的放置位置。
The syntax reference这样解释了Fixpoint
的语法:
Fixpoint ident binders {struct ident}? : type? := term
-显然,量词的语法中没有位置,该量词将 binders 和 type 上的类型变量绑定在一起。我尝试通过猜测来在forall
到处放置,但是我无法使其起作用。
我可以看到如何使 type 部分在函数参数的结果类型中变为多态,而无需触及 binders 部分:
Fixpoint map (xs: list nat): forall B, (nat -> B) -> list B := match xs with
| nil => fun _ => nil
| x::xs' => fun f => f x :: (map xs' f)
end.
—但不幸的是,这还会产生一个错误,并且对我来说还很神秘:
In environment
map : list nat -> forall B : Type, (nat -> B) -> list B
xs : list nat
T : Type
The term "nil" has type "list ?A" while it is expected to have type
"(nat -> T) -> list T".
所以,即使是这种简单的情况,我也没有解决方案。
答案 0 :(得分:4)
在Coq中,Fixpoint
命令只是fix
术语构造函数的包装,它使我们能够定义匿名递归函数。 map
的直接定义如下:
Require Import Coq.Lists.List.
Import ListNotations.
Definition map_anon : forall A B, (A -> B) -> list A -> list B :=
fix map A B (f : A -> B) (l : list A) : list B :=
match l with
| [] => []
| x :: l => f x :: map A B f l
end.
从道德上讲,它等同于以下定义:
Fixpoint map A B (f : A -> B) (l : list A) : list B :=
match l with
| [] => []
| x :: l => f x :: map A B f l
end.
请注意,A
和B
被绑定为常规变量:在Coq中,类型和术语之间没有区别,并且这些声明使Coq推断其类型为Type
。 。定义不需要forall
量词。
答案 1 :(得分:1)
您可以在函数名称后列出所有参数,包括类型参数。您将把依赖于其他参数的所有参数放在它们所依赖的参数之后。
Fixpoint map (A B: Type) (xs: list A) (f: A -> B): list B :=
[...]
如果您更喜欢forall
,则只需将所有内容(递归参数及其依赖的任何参数除外)移到:
之后。
Fixpoint map (A B: Type) (xs: list A): forall (f: A -> B), list B :=
[...]
这里要注意两件事。由于f
之后的所有内容都不取决于f
,因此可以使用->
表示法。这纯粹是表示法,没有任何语义差异。
Fixpoint map (A B: Type) (xs: list A): (A -> B) -> list B :=
[...]
要注意的另一件事是,当参数位于:
之后时,我们必须定义一个函数,而不仅仅是list B
中的某个东西。
Fixpoint map (A B: Type) (xs: list A): (A -> B) -> list B :=
fun f => [...]
这就是为什么您收到错误The term "nil" has type "list ?A" while it is expected to have type "(nat -> T) -> list T".
的原因。我们需要一个函数,而不仅仅是list B
类型的nil
类型的函数。