如何创建多态的“ map xs f”函数?

时间:2019-07-23 19:04:05

标签: coq parametric-polymorphism

问题陈述。

考虑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".

所以,即使是这种简单的情况,我也没有解决方案。

那该怎么办?

2 个答案:

答案 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.

请注意,AB被绑定为常规变量:在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类型的函数。