Zulip Chat Archive
Stream: lean4
Topic: Application type mismatch in inductive type
Yicheng Qian (Jul 25 2023 at 01:24):
I came across an "application type mismatch" problem when I was trying to define an inductive type. I managed to reduce it to this example:
inductive WF.{u} : ((α : Type u) × α) → Type (u + 1)
| ofApp (α β : Type u) (fn : α → β) (arg : α) : WF ⟨β, fn arg⟩
How can I fix this?
Yury G. Kudryashov (Jul 25 2023 at 01:29):
β
has type Type u
, not α
.
Yicheng Qian (Jul 25 2023 at 01:37):
Where is the β
that has type α
?
Mario Carneiro (Jul 25 2023 at 01:38):
it helps to show the error message:
application type mismatch
WF.ofApp α β fn
argument has type
α✝ → β
but function has type
(fn : α → β) → (arg : α) → WF { fst := β, snd := fn arg }
Yicheng Qian (Jul 25 2023 at 01:39):
Yeah, I saw that. I was wondering what is α✝
.
Mario Carneiro (Jul 25 2023 at 01:40):
it appears that there is a second α
in scope, at least somewhere internal to the inductive validity check
Yicheng Qian (Jul 25 2023 at 01:40):
If I change (Type (u + 1))
to Prop
, the error disappears.
Yicheng Qian (Jul 25 2023 at 01:41):
But Type (u + 1)
should be a valid universe level for this inductive type.
Yicheng Qian (Jul 25 2023 at 01:45):
Also this works:
inductive WF.{u} : ((α : Type u) × α) → Type (u + 1)
| ofApp (α β : Type u) (fnarg : (α → β) × α) : WF ⟨β, fnarg.1 fnarg.2⟩
Mario Carneiro (Jul 25 2023 at 01:46):
minimized some more:
inductive WF : Nat → Type 1
| mk (α : Type) (fn : α → Nat) (arg : α) : WF (fn arg)
application type mismatch
WF.mk α fn
argument has type
α✝ → Nat
but function has type
(fn : α → Nat) → (arg : α) → WF (fn arg)
Mario Carneiro (Jul 25 2023 at 01:46):
it does seem to be a bug
Mario Carneiro (Jul 25 2023 at 01:55):
it looks like the failure is somewhere in mkInjectiveTheorems
Mario Carneiro (Jul 25 2023 at 01:55):
and indeed setting set_option genInjectivity false in
makes the issue go away
Mario Carneiro (Jul 25 2023 at 02:02):
here's the lean equivalent of what mkInjectiveTheorems
does:
set_option genInjectivity false in
inductive WF : Nat → Type 1
| mk (α : Type) (fn : α → Nat) (arg : α) : WF (fn arg)
example :
∀ {α : Type} {fn : α → Nat} {arg : α} {α_1 : Type}, WF.mk α fn arg = WF.mk α_1 fn arg → α = α_1 :=
fun {α} {fn} {arg} {α_1} x ↦ WF.noConfusion x fun α_eq fn_eq arg_eq ↦ α_eq
application type mismatch
WF.mk α_1 fn
argument
fn
has type
α → Nat : Type
but is expected to have type
α_1 → Nat : Type
Mario Carneiro (Jul 25 2023 at 02:03):
it is a fair point that it's not clear what the statement of the injectivity theorem for this inductive should be
Mario Carneiro (Jul 25 2023 at 02:05):
here's what it looks like for a very similar variation on the inductive type that works:
set_option genInjectivity false in
inductive WF : Nat → Type 1
| mk (α : Type) (fn : α → Nat) (arg : α) (x) : x = fn arg → WF x
example :
∀ {α : Type} {fn : α → Nat} {arg : α} {x : Nat} {a : x = fn arg} {α_1 : Type} {fn_1 : α_1 → Nat} {arg_1 : α_1}
{a_1 : x = fn_1 arg_1}, WF.mk α fn arg x a = WF.mk α_1 fn_1 arg_1 x a_1 → α = α_1 ∧ HEq fn fn_1 ∧ HEq arg arg_1 :=
fun {α} {fn} {arg} {x} {a} {α_1} {fn_1} {arg_1} {a_1} x_1 ↦
WF.noConfusion x_1 fun α_eq fn_eq arg_eq x_eq ↦ { left := α_eq, right := { left := fn_eq, right := arg_eq } }
Yicheng Qian (Jul 25 2023 at 03:01):
Mario Carneiro said:
it is a fair point that it's not clear what the statement of the injectivity theorem for this inductive should be
What about
example :
∀ {α : Type} {fn : α → Nat} {arg : α} {fn_1 : α_1 → Nat} {arg_1 : α_1},
HEq (WF.mk α fn arg) (WF.mk α_1 fn_1 arg_1) → α = α_1 ∧ HEq fn fn_1 ∧ HEq arg arg_1 := sorry
Mario Carneiro (Jul 25 2023 at 03:07):
I pushed a basic fix as lean4#2355, which solves the issue by treating not only fn
and arg
, but also α
, as fixed because they are required for the type of the equality to work out. In this case that means there is nothing to equate and so no theorem is generated, but you can add another argument and it will assert equality of those arguments
Mario Carneiro (Jul 25 2023 at 03:09):
Yicheng Qian said:
Mario Carneiro said:
it is a fair point that it's not clear what the statement of the injectivity theorem for this inductive should be
What about
example : ∀ {α : Type} {fn : α → Nat} {arg : α} {fn_1 : α_1 → Nat} {arg_1 : α_1}, HEq (WF.mk α fn arg) (WF.mk α_1 fn_1 arg_1) → α = α_1 ∧ HEq fn fn_1 ∧ HEq arg arg_1 := sorry
This theorem is (surprisingly) not true, as it relies on the injectivity of WF
the type constructor itself, which is a non-theorem in lean's axiomatics
Yicheng Qian (Jul 25 2023 at 05:01):
What about this (fine-grained control which ensures that the arguments of WF
are equal):
(I've renamed WF
to SigmaFn
)
inductive DepEq {α : Sort u} (f : α → Sort v) : {x : α} → (a : f x) → {y : α} → (b : f y) → Prop where
/-- Reflexivity of dependent equality. -/
| refl (x : α) (a : f x) : DepEq f a a
set_option genInjectivity false in
inductive SigmaFn : Nat → Type 1
| mk (α : Type) (fn : α → Nat) (arg : α) : SigmaFn (fn arg)
theorem SigmaFn.inj {α : Type} {fn : α → Nat} {arg : α} {fn_1 : α_1 → Nat} {arg_1 : α_1}
(H : DepEq SigmaFn (SigmaFn.mk α fn arg) (SigmaFn.mk α_1 fn_1 arg_1)) : α = α_1 ∧ HEq arg arg_1 ∧ HEq fn fn_1
Yicheng Qian (Jul 25 2023 at 05:02):
Proof:
inductive DepEq {α : Sort u} (f : α → Sort v) : {x : α} → (a : f x) → {y : α} → (b : f y) → Prop where
/-- Reflexivity of dependent equality. -/
| refl (x : α) (a : f x) : DepEq f a a
set_option genInjectivity false in
inductive SigmaFn : Nat → Type 1
| mk (α : Type) (fn : α → Nat) (arg : α) : SigmaFn (fn arg)
def HEq.ofSigmaEq {α β : Type u} (x : α) (y : β) (H : @Sigma.mk _ id _ x = @Sigma.mk _ id _ y) : HEq x y :=
by cases H; apply HEq.rfl
def DepEq.toSigmaEq {α : Type u} (f : α → Type v) (x : α) (a : f x)
(y : α) (b : f y) (H : DepEq f a b) : Sigma.mk (β:=f) x a = Sigma.mk (β:=f) y b :=
by cases H; rfl
theorem SigmaFn.inj {α : Type} {fn : α → Nat} {arg : α} {fn_1 : α_1 → Nat} {arg_1 : α_1}
(H : DepEq SigmaFn (SigmaFn.mk α fn arg) (SigmaFn.mk α_1 fn_1 arg_1)) : α = α_1 ∧ HEq arg arg_1 ∧ HEq fn fn_1 :=
let lh : Sigma SigmaFn := { fst := fn arg, snd := mk α fn arg }
let rh : Sigma SigmaFn := { fst := fn_1 arg_1, snd := mk α_1 fn_1 arg_1 }
let lreq : lh = rh := DepEq.toSigmaEq _ _ _ _ _ H
let rwFn₁ (x : Sigma SigmaFn) : Sigma id :=
match x with
| Sigma.mk fst snd =>
match snd with
| SigmaFn.mk α fn arg => ⟨α, arg⟩
let rwRes₁ : rwFn₁ lh = rwFn₁ rh := by rw [lreq]
let argHeq := HEq.ofSigmaEq _ _ rwRes₁;
let rwFn₂ (x : Sigma SigmaFn) : Sigma id :=
match x with
| Sigma.mk fst snd =>
match snd with
| SigmaFn.mk α fn arg => ⟨α → Nat, fn⟩
let rwRes₂ : rwFn₂ lh = rwFn₂ rh := by rw [lreq]
let fnHeq := HEq.ofSigmaEq _ _ rwRes₂;
And.intro (by cases argHeq; rfl) (And.intro argHeq fnHeq)
Yicheng Qian (Jul 25 2023 at 05:05):
If there are multiple arguments to the type constructor, we can bundle them by dependent pair.
Yicheng Qian (Jul 25 2023 at 05:42):
(deleted)
Yicheng Qian (Jul 25 2023 at 05:43):
(deleted)
Yicheng Qian (Jul 25 2023 at 05:52):
DepEq
and HEq
are probably not necessary. They can be modeled by Sigma/PSigma
plus Eq
.
Yicheng Qian (Jul 25 2023 at 06:18):
theorem SigmaFn.inj {α : Type} {fn : α → Nat} {arg : α} {fn_1 : α_1 → Nat} {arg_1 : α_1}
(H : (⟨fn arg, SigmaFn.mk α fn arg⟩ : Sigma SigmaFn) = ⟨fn_1 arg_1, SigmaFn.mk α_1 fn_1 arg_1⟩) :
α = α_1 ∧ (⟨α, arg⟩ : Sigma id) = ⟨α_1, arg_1⟩ ∧ (⟨α, fn⟩ : Sigma (fun α => α → Nat)) = ⟨α_1, fn_1⟩ :=
let lh : Sigma SigmaFn := ⟨fn arg, SigmaFn.mk α fn arg⟩
let rh : Sigma SigmaFn := ⟨fn_1 arg_1, SigmaFn.mk α_1 fn_1 arg_1⟩
let lreq : lh = rh := H
let rwFn₁ (x : Sigma SigmaFn) : Sigma id :=
match x with
| Sigma.mk fst snd =>
match snd with
| SigmaFn.mk α fn arg => ⟨α, arg⟩
let rwRes₁ : rwFn₁ lh = rwFn₁ rh := by rw [lreq]
let rwFn₂ (x : Sigma SigmaFn) : Sigma (fun (α : Type) => α → Nat) :=
match x with
| Sigma.mk fst snd =>
match snd with
| SigmaFn.mk α fn arg => ⟨α, fn⟩
let rwRes₂ : rwFn₂ lh = rwFn₂ rh := by rw [lreq]
And.intro (by cases rwRes₁; rfl) (And.intro rwRes₁ rwRes₂)
Last updated: Dec 20 2023 at 11:08 UTC