Zulip Chat Archive
Stream: new members
Topic: Uniqueness of inductive types
Patrick Johnson (Nov 15 2021 at 15:04):
Given two definitions of inductive types, can we prove that the types are distinct? For example:
inductive A : Type
| mk1 : A
inductive B : Type
| mk1 : B
| mk2 : B
Can we always prove something like lemma a_ne_b : A ≠ B
? In this particular case it can be proved using heterogeneous equality, because they have different cardinalities. But is it possible in general?
Reid Barton (Nov 15 2021 at 15:07):
You can only prove it if they have different cardinalities
Kyle Miller (Nov 15 2021 at 16:22):
The mental model I have is that Lean is only promising that it's able to implement the type for you in some way. Since everything is typechecked, elements don't need to know what type they're from, so in principle it could reuse representations between different types.
For example, it wouldn't be wrong for Lean to take
inductive my_list (α : Type*)
| nil : my_list
| cons : α → my_list → my_list
and compile it like this:
def my_list (α : Type*) := list α
def my_list.nil {α : Type*} : my_list α := list.nil
def my_list.cons {α : Type*} (x : α) (xs : my_list α) : my_list α := list.cons x xs
def my_list.rec ...
...
Lean only lets you prove things that are independent of how it might be implementing things behind the scenes, which is why list α = my_list α
is neither provable nor disprovable.
Kyle Miller (Nov 15 2021 at 16:28):
Also, it turns out that even if the arguments to a type constructor are different, the resulting types might be the same. In fact, there must be cases where this happens by a diagonalization argument: https://leanprover.zulipchat.com/#narrow/stream/113489-new-members/topic/disjointness.20of.20inductive.20type.20constructors.2C.20heq/near/204877510
Stuart Presnell (Nov 15 2021 at 16:54):
Could we prove a weaker relation between list
and my_list
in this case? Is there a suitable notion of isomorphism or equivalence?
Kyle Miller (Nov 15 2021 at 17:06):
You could create an docs#equiv and show it carries my_list.nil
to list.nil
and my_list.cons
to list.cons
(i.e., show it's an isomorphism)
Stuart Presnell (Nov 15 2021 at 17:09):
Ok. And since we don't have univalence we couldn't derive from this isomorphism that they're equal. :)
Kyle Miller (Nov 15 2021 at 17:12):
Just to be completely explicit:
import tactic
inductive my_list (α : Type*)
| nil : my_list
| cons : α → my_list → my_list
variables {α : Type*}
def my_list.to_list : my_list α → list α
| my_list.nil := list.nil
| (my_list.cons x xs) := list.cons x xs.to_list
def list.to_my_list : list α → my_list α
| list.nil := my_list.nil
| (list.cons x xs) := my_list.cons x xs.to_my_list
def my_list_equiv : my_list α ≃ list α :=
{ to_fun := my_list.to_list,
inv_fun := list.to_my_list,
left_inv :=
begin
intro l,
induction l with x xs ih,
{ refl },
{ simp! [ih], },
end,
right_inv :=
begin
intro l,
induction l with x xs ih,
{ refl },
{ simp! [ih], },
end }
lemma my_list_equiv.nil : my_list_equiv (my_list.nil : my_list α) = list.nil := rfl
lemma my_list_equiv.cons (x : α) (xs : my_list α) :
my_list_equiv (my_list.cons x xs) = list.cons x (my_list_equiv xs) := rfl
-- Forgetting the definition of `my_list_equiv`, similar lemmas for `my_list_equiv.symm` follow.
Last updated: Dec 20 2023 at 11:08 UTC