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.