(* I post my answer as a Coq file. In it I show that supercoooldave's
definition of a universal tree is not what he intended. His isUniv
means "the tree has an infinite branch". I provide the correct
definition, show that the universal tree is universal according to
the new definition, and I provide counter-examples to
supercooldave's definition. I also point out that the universal
tree of branching type A has an infinite path iff A is inhabited.
*)
Set Implicit Arguments.
CoInductive Tree (A : Set): Set := Node : (A -> option (Tree A)) -> Tree A.
Definition child (A : Set) (t : Tree A) (a : A) :=
match t with
Node f => f a
end.
(* We consider two trees, one is the universal tree on A (always
branches out fully), and the other is a binary tree which always
branches to one side and not to the other, so it is like an
infinite path with branches of length 1 shooting off at each node. *)
CoFixpoint Univ (A : Set) : Tree A := Node (fun _ => Some (Univ A)).
CoFixpoint Thread : Tree (bool) :=
Node (fun (b : bool) => if b then Some Thread else None).
(* The original definition of supercooldave should be called "has an
infinite path", so we rename it to "hasInfinitePath". *)
CoInductive hasInfinitePath (A : Set) : Tree A -> Prop :=
haspath : forall (f : A -> option (Tree A)) (a : A) (t : Tree A),
f a = Some t ->
hasInfinitePath t ->
hasInfinitePath (Node f).
(* The correct definition of universal tree. *)
CoInductive isUniv (A : Set) : Tree A -> Prop :=
isuniv : forall (f : A -> option (Tree A)),
(forall a, exists t, f a = Some t /\ isUniv t) ->
isUniv (Node f).
(* Technicalities that allow us to get coinductive proofs done. *)
Definition TT (A : Set) (t : Tree A) :=
match t with
| Node o => Node o
end.
Lemma TTid (A : Set) : forall t: Tree A, t = TT t.
intros A t.
destruct t.
reflexivity.
Qed.
(* Thread has an infinite path. *)
Lemma ThreadHasInfinitePath : hasInfinitePath Thread.
Proof.
cofix H.
rewrite TTid.
unfold TT.
unfold Thread.
(* there is a path down the "true" branch leading to Thread. *)
apply haspath with (a := true) (t := Thread).
auto.
auto.
Qed.
(* Auxiliary lemma *)
Lemma univChildNotNone (A : Set) (t : Tree A) (a : A):
isUniv t -> (child t a <> None).
Proof.
intros A t a [f H].
destruct (H a) as [u [G _]].
unfold child.
rewrite G.
discriminate.
Qed.
(* Thread is not universal. *)
Lemma ThreadNotUniversal: ~ (isUniv Thread).
Proof.
unfold not.
intro H.
eapply univChildNotNone with (t := Thread) (a := false).
auto.
unfold Thread, child.
auto.
Qed.
(* Now let us show that Univ is universal. *)
Lemma univIsuniv (A : Set): isUniv (Univ A).
Proof.
intro A.
cofix H.
rewrite TTid.
unfold TT.
unfold Univ.
apply isuniv.
intro a.
exists (Univ A).
auto.
Qed.
(* By the way, it need not be the case that a universal tree has
an infinite path! In fact, the universal tree of branching type
A has an infinite path iff A is inhabited. *)
Lemma whenUnivHasInfiniteBranch (A : Set):
hasInfinitePath (Univ A) <-> exists a : A, True.
Proof.
intro A.
split.
intro H.
destruct H as [f a t _].
exists a.
trivial.
intros [a _].
cofix H.
rewrite TTid.
unfold TT.
unfold Univ.
apply haspath with (t := Univ A); auto.
Qed.