3
votes

I am new to Coq and need some help with some of trivial examples to get me started. In particular I am interested in defining some operations of vectors (fixed size lists) using dependent types. I started with Vector package and trying to implement some additional functions. For example I am having difficulty implementing trivial 'take' and 'drop' functions, which take or drop first 'p' elements from the list.

Require Import Vector.

Fixpoint take {A} {n} (p:nat) (a: t A n) : p<=n -> t A p := 
   match a return ( p<=n -> t A p) with
     | cons A v (S m) => cons (hd v) (take m (tl v)) m
     | nil => fun pf => a
   end.

The error (in case of nil) is:

The term "a" has type "t A n" while it is expected to have type "t A p".

Could somebody help me with some starting points? Thanks!

1
I don't know how to answer your question, but there's a good book that I bought a while back when I was thinking about getting serious about learning Coq. It's called, "Interactive Theorem Proving and Development." Also, this question might be better suited for cs.se, but I'm not sure. - Philip White
@PhilipWhite This isn't any more on-topic on Computer Science than here, as it's strictly about programming in Coq, and not about understanding the theoretical underpinnings. This question would be fine on Stack Overflow. - Gilles 'SO- stop being evil'
@krokodil -- this question is off-topic here, as it is not about cs theory. I can migrate your question stack overflow if you'd like. Otherwise, this question will be closed soon as off topic. - Lev Reyzin
Sorry for using wrong forum. Feel free to move to stack overflow. - krokodil

1 Answers

5
votes

I don't understand your approach. You're always returning a non-empty vector when the argument is a non-empty vector, but take must return nil when p=0 regardless of the vector.

Here's one approach to building take. Rather than using the hypothesis p <= n, I express the length of the argument n as a sum of the number p of elements to take and the number of trailing elements m, which is possible iff p <= n. This allows for an easier recursive definition, because (S p') + m is structurally equal to S (p' + m). Note that the discrimination is on the number of elements to take: return nil if taking 0, return cons head new_tail otherwise.

This version of the take function has the desired computational behavior, so all that's left is to define one with the desired proof content. I use the Program feature to do this conveniently: fill in the computational content (trivial, I just need to say that I want to use m = n - p), then complete the proof obligations (which are simple arithmetic).

Require Import Arith.
Require Import Vector.

Fixpoint take_plus {A} {m} (p:nat) : t A (p+m) -> t A p := 
   match p return t A (p+m) -> t A p with
     | 0 => fun a => nil _
     | S p' => fun a => cons A (hd a) _ (take_plus p' (tl a))
   end.
Program Definition take A n p (a : t A n) (H : p <= n) : t A p :=
          take_plus (m := n - p) p a.
Solve Obligations using auto with arith.

For your newdrop : forall A n p, t A n -> p <= n -> t A (n-p), the following approach works. You need to help Coq by telling it what p and n become in the recursive call.

Program Fixpoint newdrop  {A} {n} p : t A n -> p <= n -> t A (n-p) :=
   match p return t A n -> p <= n -> t A (n-p) with
     | 0 => fun a H => a
     | S p' => fun a H => newdrop p' (tl a) (_ : p' <= n - 1)
   end.
Next Obligation.
omega.
Qed.
Next Obligation.
omega.
Qed.
Next Obligation.
omega.
Qed.
Next Obligation.
omega.
Qed.

I don't know why Solve Obligations using omega. doesn't work but solving each obligation individually works.