Using a language similar to Morte/CoC, I'm trying to prove the simple statement there are lists of arbitrary lengths
. For that, I wrote the following type:
∀ n:Nat ->
(ThereIs (List Nat)
(Equal Nat
(List.length Nat l)
n)))
ThereIs
is the dependent pair (Sigma). All is church-encoded. To prove it, I wrote the following proof:
λ n:Nat ->
(ThereIs.this (List Nat)
(λ l:(List Nat) -> (Equal Nat (List.length Nat l) n))
(List.replicate Nat n Nat.Zero)
(Equal.refl Nat n))
Weirdly, I get a type mismatch error between d
(i.e., the free variable of type Nat) and λ c:* -> λ b:(c -> c) -> λ a:c -> (d c b a)
. But that later term, when eta-reduced, is just d
! Since I don't have an eta-reducer ready, I instead made this following "useless identify" function:
λ n: Nat ->
λ Nat:* ->
λ Succ: (Nat -> Nat) ->
λ Zero: Nat ->
(n Nat Succ Zero)
Now, by applying that useless id to every occurence of n
, I "un-eta" it, causing the proof to check. I'd like to gain any kind of insight of what is going on here. Is this "useless id" function a known/used pattern on writing proofs? Why isn't the calculus of contructions able to type-check this proof without this little help? Is there any deep reasoning behind this phenomena or is it just how things are for no special reason?
id
s of all varieties -- not just eta equalities -- are very common in proof systems. Half the tactics in Coq end up translating intoid
spelled in an especially exciting way. – Daniel Wagnerl
fromList.length Nat l
bound? Instead of eta-reduction you can incorporate eta-expansion in your type checker: an attempt to unifyf
with\x -> e
results in eta-expandingf
, so the unification problem becomes(\x -> f x) =?= (\x -> e)
and you can proceed further structurally. Ideally this machinery should be type-directed, so e.g. whenever two expressions of typeTop
are unified, you don't need to unify them structurally and can just conclude that they are the same. – user3237465