Coq inference behavior
Question
I'm trying to write the following Agda snippet in Coq.
open import Data.Fin using (Fin; suc; zero)
open import Data.Nat using (ℕ; suc; zero)
thin : {n : ℕ} -> Fin (suc n) -> Fin n -> Fin (suc n)
thin zero y = suc y
thin (suc x) zero = zero
thin (suc x) (suc y) = suc (thin x y)
I thought this could be straightforwardly translated to Coq as:
Inductive Fin : nat -> Type := | fz {n : nat} : Fin (S n) | fs {n : nat} : Fin n -> Fin (S n).
I believe Coq should be able to figure out the implicit parameter n so I have no idea what is going on. I think I am unaware of a difference between the type systems of Agda and Coq since the former typechecks fine.
Answer
When pattern matching with dependent types, Coq does not usually consider some essential relations between the variables in the context and the variables introduced in the branches.
The easiest solution is to define the function in proof mode, at least to understand what is going on.
This gives:
thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
x: Fin (S n)
y: Fin nFin (S n)thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
x: Fin (S n)
y: Fin nFin (S n)thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n, n1: nat
Heqn1: n1 = S n
x: Fin n1
y: Fin nFin n1thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
y: Fin nFin (S n)thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
x, y: Fin nFin (S n)thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
y: Fin nFin (S n)assumption.thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
y: Fin nFin nthin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
x, y: Fin nFin (S n)thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
x: Fin (S n)Fin (S (S n))thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
x: Fin (S n)
y: Fin nFin (S (S n))apply fz.thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
x: Fin (S n)Fin (S (S n))thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
x: Fin (S n)
y: Fin nFin (S (S n))apply thin; assumption. Defined. (* to create a transparent constant, as given by a classic Fixpoint *)thin: forall n : nat, Fin (S n) -> Fin n -> Fin (S n)
n: nat
x: Fin (S n)
y: Fin nFin (S n)
You can then print the value and read the lambda term to understand how to define it directly. This could give:
The return clauses of the pattern matchings is used to solve the problem presented above: they connect the variables introduced in the branches and the ones in the context. This is discussed more deeply here: http://adam.chlipala.net/cpdt/html/MoreDep.html.
Also note that this particular inductive type was discussed a few weeks ago on the coq-club mailing list. See https://sympa.inria.fr/sympa/arc/coq-club/2016-03/msg00206.html.
Q: This helps a lot, thanks! I should have finished Chlipala's book before actually trying to do stuff in Coq. One more question I have: is it considered bad practice to define functions in proof mode?
A: I don't really know. Usually, I do that to check the lambda term and write it myself. Anyway, I try to use mostly low-level tactics to create a readable lambda term. Tactics like inversion create
A: Tactics like inversion create non-natural terms and should be avoided. Maybe other users have stronger opinions on this particular subject.