-- PCF/Flat.lean

import «PCF».Domain

inductive Flat (α : Type) : Type where
  | none : Flat α
  | some : α → Flat α

open Classical

noncomputable def flat_sup (c : Chain (Flat α)) : Flat α :=
  if p : ∃ a n, c.act n = .some a then .some p.choose else .none

-- Repository definitions used:
content: def Chain (α : Type i) [Order α] := Mono Nat α

content: class Order (α) where
  R : α → α → Prop
  refl {x} : R x x
  trans {x y z} : R x y → R y z → R x z
  anti {x y} : R x y → R y x → x = y

content: structure Mono (α) (β) [Order α] [Order β] where
  act : α → β
  act' : is_monotone act

content: def is_monotone [Order α] [Order β] (f : α → β) := ∀ {x y : α}, x ⊑ y → f x ⊑ f y

content: infix:100 " ⊑ " => Order.R

content: infix:100 " ⇄! " => Order.anti

content: infixl:100 " • " => Mono.act'

content: notation:101 f " • " x:100 => Mono.act' (Cont.fn f) x

-- Repository lemmas used:
content: theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :\n(l₁ ++ l₂)[i] = l₁[i]

-- Local definitions used:
content: inductive Flat (α : Type) : Type where
  | none : Flat α
  | some : α → Flat α

content: noncomputable def flat_sup (c : Chain (Flat α)) : Flat α :=
  if p : ∃ a n, c.act n = .some a then .some p.choose else .none

-- Local lemmas used:
content: theorem Flat.chain_some {c : Chain (Flat _)} {a b : α}
  (p : ∃ k, c.act k = .some a) (q : ∃ k, c.act k = .some b) : a = b

-- Target theorem and proof:
theorem Flat.sup_some {c : Chain _} {a : α} : (∃ k, c.act k = .some a) ↔ (flat_sup c = .some a)
:= by
  constructor
  case mp =>
    intro h;
    have p : ∃ a n, c.act n = .some a := ⟨a, h⟩
    rw [Flat.chain_some h p.choose_spec]
    exact dif_pos p
  case mpr =>
    intro h;
    if p : ∃ a n, c.act n = .some a
    then
      have q : flat_sup c = .some _ := dif_pos p
      rw [← h, q]
      exact p.choose_spec
    else
      have q : flat_sup c = .none := dif_neg p
      rw [q] at h
      exact Flat.noConfusion h