简体   繁体   中英

Do you need to pass in template types to functions that accept template objects in Coq?

I'm experimenting with lists in Coq:

Inductive list (A : Type) : Type := 
    | empty : list A 
    | cons (n : A) (l : list A).
Arguments empty {A}.
Arguments cons {A} n l.

The Arguments statements at the bottom (in addition to some Notation statements) allow me to write [1;2;3] and let the interpreter figure out what type should fill A , rather than specifying that A should be nat .

However, when I write a length function for my list objects, my approach throws errors:

Fixpoint length (l : list A) : nat :=
    match l with 
    | empty => 0
    | cons n cdr => 1 + (length cdr)
    end.

It expects that the passed-in lists are actually lists of the A type, instead of recognizing A as a template type.

The standard library takes this approach:

Definition length (A : Type) : list A -> nat :=
  fix length l :=
  match l with
   | nil => O
   | _ :: l' => S (length l')
  end.

where you're expected to pass in the type of the list, like so:

Compute length nat [1;2;3]. (* 3 *)

This seems like a serious drawback. I can't seem to define an Argument statement that solves this problem like before. Is there really no other way?

First off, the Arguments statements for list are not responsible for letting you write [1;2;3] . That is a separate Notation . Furthermore, if an argument is explicit, you can pass the expression _ for it, to request Coq to fill it in. (Ie the Notation [x; ...; z] is possible to define with or without the Arguments )

Inductive mylist (A : Type) : Type := mynil | mycons (x : A) (xs : mylist A).
Notation "[[ ]]" := (mynil _). (* note that I *can* pass in the explicit type argument without actually knowing it *)
Notation "[[ x ; .. ; y ]]" := (mycons _ x .. (mycons _ y [[]]) .. ).
Check [[]].
Check [[1;2;3]].

Understanding this already makes an explicitly type-passing length not actually that bad to use

Fixpoint mylength (A : Type) (xs : mylist A) : nat :=
  match xs with
  | mynil _ => 0
  | mycons _ _ xs => S (mylength A xs)
  end.
Compute (mylength _ [[1; 2; 3]]). (* Coq solves for [_ := nat] itself *)

All that aside, you declare an argument to be implicit by putting it in braces, how else? For a definition like mylength which was originally defined with an explicit argument, Arguments can change that:

Arguments mylength {A} xs.
Compute (mylength [[1; 2; 3]]).
(* Indeed, the standard library has Arguments length [A] xs, which is similar to using {A} (read the documentation!) and lets you say *)
Compute (length [1; 2; 3]).
 

But it is more usual to just define functions with implicit arguments from the outset.

Fixpoint mylength2 {A : Type} (xs : mylist A) : nat := (* implicit A *)
  match xs with
  | mynil _ => 0
  | mycons _ _ xs => S (mylength2 xs)
  end.
Compute (mylength2 [[1; 2; 3]]).

(You can't not declare A as a parameter of mylength / mylength2 , since the parameter type mylist A needs A to be in scope to make sense.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM