user287393
user287393

Reputation: 1241

Using contextual information in Coq pattern matching

I want to define a function app_1 which converts an n-ary function f : X ^^ n --> Y into a new function f' : (Z -> X) ^^ n --> Y, provided that there is a z : Z to apply once to all of its arguments. For instance,

Example ex1 : app_1 plus 2 S pred = 4.
trivial. Qed.

app_1 plus 2 is able to take the unary functions S and pred as arguments because it applies both of them to 2 first, and then apply the results to plus.

Here's my attempted definition of app_1:

Fixpoint app_1 {X Y Z : Type} {n : nat} 
(f : X ^^ n --> Y) (z : Z) :
(Z -> X) ^^ n --> Y :=
match n return ((Z -> X) ^^ n --> Y) with
| O    => f
| S n' => fun g => app_1 (f (g z)) z
end.

Which doesn't work, because Coq doesn't like the clause | O => f, and says:

The term "f" has type "X ^^ n --> Y" while it is expected to have type "(Z -> X) ^^ 0 --> Y".

But if n = O, X ^^ n --> Y = X ^^ 0 --> Y = Y = (Z -> X) ^^ 0 --> Y, so it's not a type mismatch. The problem is that Coq can't use the contextual information n = O to figure out the equivalence.

Some preliminary searches show that this is a well-known problem, but it's a little confusing how to apply those discussions to this case. For instance, an almost identical question on SO is solved using return, which is what I (sort of) tried above as well, to no avail.

Is there a way to make this pattern match work?

Upvotes: 2

Views: 112

Answers (2)

Ptival
Ptival

Reputation: 9437

You can just delay getting your arguments until after n has been refined:

Fixpoint app_1 {X Y Z : Type} {n : nat}
  : (X ^^ n --> Y) -> Z -> (Z -> X) ^^ n --> Y :=
  match n return (X ^^ n --> Y) -> Z -> (Z -> X) ^^ n --> Y with
    | O    => fun f _ => f
    | S n' => fun f z g => app_1 (f (g z)) z
  end.

By the time f is bound, its type has already been changed into X ^^ 0 --> Y, and so it works out.

EDIT: Ah, I was going to add this, but Arthur beat me to it!

Fixpoint app_1 {X Y Z : Type} {n : nat} (f: X ^^ n --> Y) (z: Z)
  : (Z -> X) ^^ n --> Y :=
  match n return X ^^ n --> Y -> ((Z -> X) ^^ n --> Y) with
    | O    => fun f => f
    | S n' => fun f' g => app_1 (f' (g z)) z
  end f.

Upvotes: 2

Arthur Azevedo De Amorim
Arthur Azevedo De Amorim

Reputation: 23592

As usual, you must apply the convoy pattern (cf. Adam Chlipala's CPDT book) and make the pattern-matching return a function:

Require Import Coq.Numbers.NaryFunctions.

Fixpoint app_1 {X Y Z : Type} {n : nat}
(f : X ^^ n --> Y) (z : Z) :
(Z -> X) ^^ n --> Y :=
match n return (X ^^ n --> Y) -> ((Z -> X) ^^ n --> Y) with
| O    => fun f => f
| S n' => fun f g => app_1 (f (g z)) z
end f.

In order to use the information about f's type, it needs to be re-abstracted: in each branch, it'll have the right type.

Upvotes: 3

Related Questions