Theory Coinductive_List_Prefix
section ‹Instantiation of the order type classes for lazy lists›
theory Coinductive_List_Prefix imports
  Coinductive_List
  "HOL-Library.Prefix_Order"
begin
subsection ‹Instantiation of the order type class›
instantiation llist :: (type) order begin
definition [code_unfold]: "xs ≤ ys = lprefix xs ys"
definition [code_unfold]: "xs < ys = lstrict_prefix xs ys"
instance
proof(intro_classes)
  fix xs ys zs :: "'a llist"
  show "(xs < ys) = (xs ≤ ys ∧ ¬ ys ≤ xs)"
    unfolding less_llist_def less_eq_llist_def lstrict_prefix_def
    by(auto simp: lprefix_antisym)
  show "xs ≤ xs" unfolding less_eq_llist_def by(rule lprefix_refl)
  show "⟦xs ≤ ys; ys ≤ zs⟧ ⟹ xs ≤ zs"
    unfolding less_eq_llist_def by(rule lprefix_trans)
  show "⟦xs ≤ ys; ys ≤ xs⟧ ⟹ xs = ys"
    unfolding less_eq_llist_def by(rule lprefix_antisym)
qed
end
lemma le_llist_conv_lprefix [iff]: "(≤) = lprefix"
by(simp add: less_eq_llist_def fun_eq_iff)
lemma less_llist_conv_lstrict_prefix [iff]: "(<) = lstrict_prefix"
by(simp add: less_llist_def fun_eq_iff)
instantiation llist :: (type) order_bot begin
definition "bot = LNil"
instance
by(intro_classes)(simp add: bot_llist_def)
end
lemma llist_of_lprefix_llist_of [simp]:
  "lprefix (llist_of xs) (llist_of ys) ⟷ xs ≤ ys"
proof(induct xs arbitrary: ys)
  case (Cons x xs) thus ?case
    by(cases ys)(auto simp add: LCons_lprefix_conv)
qed simp
subsection ‹Prefix ordering as a lower semilattice›
instantiation llist :: (type) semilattice_inf begin
definition [code del]:
  "inf xs ys = 
   unfold_llist (λ(xs, ys). xs ≠ LNil ⟶ ys ≠ LNil ⟶ lhd xs ≠ lhd ys)
     (lhd ∘ snd) (map_prod ltl ltl) (xs, ys)"
lemma llist_inf_simps [simp, code, nitpick_simp]:
  "inf LNil xs = LNil"
  "inf xs LNil = LNil"
  "inf (LCons x xs) (LCons y ys) = (if x = y then LCons x (inf xs ys) else LNil)"
unfolding inf_llist_def by simp_all
lemma llist_inf_eq_LNil [simp]:
  "lnull (inf xs ys) ⟷ (xs ≠ LNil ⟶ ys ≠ LNil ⟶ lhd xs ≠ lhd ys)"
by(simp add: inf_llist_def)
lemma [simp]: assumes "xs ≠ LNil" "ys ≠ LNil" "lhd xs = lhd ys"
  shows lhd_llist_inf: "lhd (inf xs ys) = lhd ys"
  and  ltl_llist_inf: "ltl (inf xs ys) = inf (ltl xs) (ltl ys)"
using assms by(simp_all add: inf_llist_def)
instance
proof
  fix xs ys zs :: "'a llist"
  show "inf xs ys ≤ xs" unfolding le_llist_conv_lprefix
    by(coinduction arbitrary: xs ys) auto
  show "inf xs ys ≤ ys" unfolding le_llist_conv_lprefix
    by(coinduction arbitrary: xs ys) auto
  assume "xs ≤ ys" "xs ≤ zs"
  thus "xs ≤ inf ys zs" unfolding le_llist_conv_lprefix
  proof(coinduction arbitrary: xs ys zs)
    case (lprefix xs ys zs)
    thus ?case by(cases xs)(auto 4 4 simp add: LCons_lprefix_conv)
  qed
qed
end
lemma llength_inf [simp]: "llength (inf xs ys) = llcp xs ys"
by(coinduction arbitrary: xs ys rule: enat_coinduct)(auto simp add: llcp_eq_0_iff epred_llength epred_llcp)
instantiation llist :: (type) ccpo
begin
definition "Sup A = lSup A"
instance
  by intro_classes
     (auto simp: Sup_llist_def less_eq_llist_def[abs_def] intro!: llist.lub_upper llist.lub_least)
end
end