{-# OPTIONS --safe #-} open import Prelude module Codata.Chain {ℓ} (S : Type ℓ) where open import Data.Link S record Chain (A : Type a) : Type (ℓ ℓ⊔ a) where coinductive; constructor _◂_ field head : A tail : Link (Chain A) open Chain module _ (ψ : A → B × Link A) where ana : A → Chain B ana′ : B × Link A → Chain B map-ana : Link A → Link (Chain B) ana = ana′ ∘ ψ ana′ r .head = r .fst ana′ r .tail = map-ana (r .snd) map-ana (w ∝ x) = w ∝ ana x map-ana ⟨⟩ = ⟨⟩ cout : Chain A → A × Link (Chain A) cout = head ▵ tail map-chain : (A → B) → Chain A → Chain B map-chain f = ana (map₁ f ∘ cout) module _ (f : A → B) (ψ : C → A × Link C) where map∘ana : ∀ r → map-chain f (ana ψ r) ≡ ana (map₁ f ∘ ψ) r map∘ana′ : ∀ r → map-ana (map₁ f ∘ cout) (map-ana ψ r) ≡ map-ana (map₁ f ∘ ψ) r map∘ana r i .head = f (ψ r .fst) map∘ana r i .tail = map∘ana′ (ψ r .snd) i map∘ana′ (s ∝ x) = cong (s ∝_) (map∘ana x) map∘ana′ ⟨⟩ = refl module _ (R : A → A → Type c) where R″ : Link A → Link A → Type (ℓ ℓ⊔ c) R″ ⟨⟩ ⟨⟩ = Poly-⊤ R″ (x ∝ xs) (y ∝ ys) = (x ≡ y) × R xs ys R″ _ _ = Poly-⊥ R′ : B × Link A → B × Link A → Type _ R′ (x , xs) (y , ys) = x ≡ y × R″ xs ys module _ (ψ : A → B × Link A) (p : ∀ x y → R x y → R′ (ψ x) (ψ y)) where ana-bisim : ∀ x y → R x y → ana ψ x ≡ ana ψ y ana-bisim′ : ∀ x y → R″ x y → map-ana ψ x ≡ map-ana ψ y ana-bisim x y r i .head = p x y r .fst i ana-bisim x y r i .tail = ana-bisim′ (ψ x .snd) (ψ y .snd) (p x y r .snd) i ana-bisim′ (x ∝ xs) (y ∝ ys) (r , rs) = cong₂ _∝_ r (ana-bisim xs ys rs) ana-bisim′ ⟨⟩ ⟨⟩ r = refl Chain⁺ : Type a → Type (ℓ ℓ⊔ a) Chain⁺ A = Link (Chain A) tabulate : (ℕ → Link A) → Chain⁺ A tabulate⁺ : (ℕ → Link A) → Link A → Chain⁺ A tabulate′ : (ℕ → Link A) → A → Chain A tabulate f = tabulate⁺ f (f zero) tabulate⁺ f (s ∝ x) = s ∝ tabulate′ f x tabulate⁺ f ⟨⟩ = ⟨⟩ tabulate′ f x .head = x tabulate′ f x .tail = tabulate (f ∘ suc) open import Data.Nat.Order module _ {A : Type a} where _≲_ : Maybe A → Maybe A → Type _ just x ≲ y = ⊤ nothing ≲ just _ = ⊥ nothing ≲ nothing = ⊤ isProp-≲ : ∀ {x y} → isProp (x ≲ y) isProp-≲ {fsuc x} {y} _ _ = refl isProp-≲ {⟨⟩} {fsuc x} () isProp-≲ {⟨⟩} {⟨⟩} _ _ = refl module _ {A : Type a} where index : Chain⁺ A → ℕ → Link A index′ : S → Chain A → ℕ → Link A index′ s xs zero = s ∝ head xs index′ s xs (suc n) = index (tail xs) n index ⟨⟩ _ = nothing index (s ∝ xs) = index′ s xs final : (ℕ → Link A) → Type _ final p = ∀ m n → m ≤ n → p m ≲ p n final-ind : ∀ xs → final (index xs) final-ind ⟨⟩ m n m≤n = tt final-ind (s ∝ x) zero zero m≤n = tt final-ind (s ∝ x) zero (suc n) m≤n = tt final-ind (s ∝ x) (suc m) (suc n) m≤n = final-ind (tail x) m n m≤n isProp-final : ∀ f → isProp (final f) isProp-final f = isPropΠ λ m → isPropΠ λ n → isProp→ isProp-≲ index∘tabulate : ∀ f → final f → ∀ n → index (tabulate f) n ≡ f n index∘tabulate f p zero with f zero index∘tabulate f p zero | _ ∝ _ = refl index∘tabulate f p zero | ⟨⟩ = refl index∘tabulate f p (suc n) with f zero | f (suc n) | inspect f (suc n) | p zero (suc n) tt ... | s ∝ x | _ | 〖 fs 〗 | q = index∘tabulate (f ∘ suc) (λ m n → p (suc m) (suc n)) n ; fs ... | ⟨⟩ | ⟨⟩ | _ | q = refl tabulate∘index : ∀ x → tabulate (index x) ≡ x tabulate∘index′ : ∀ s x → tabulate′ (index′ s x) (head x) ≡ x tabulate∘index ⟨⟩ i = ⟨⟩ tabulate∘index (s ∝ x) i = s ∝ tabulate∘index′ s x i tabulate∘index′ s x i .head = head x tabulate∘index′ s x i .tail = tabulate∘index (tail x) i Chain⁺′ : Type a → Type _ Chain⁺′ A = Σ (ℕ → Link A) final open import Cubical.Data.Sigma using (Σ≡Prop) chain⁺-iso : Chain⁺ A ⇔ Chain⁺′ A chain⁺-iso .fun xs .fst = index xs chain⁺-iso .fun xs .snd = final-ind xs chain⁺-iso .inv (xs , _) = tabulate xs chain⁺-iso .rightInv (f , p) = Σ≡Prop isProp-final (funExt (index∘tabulate f p)) chain⁺-iso .leftInv = tabulate∘index chain-iso : Chain A ⇔ (A × Chain⁺ A) chain-iso .fun xs = xs .head , xs .tail chain-iso .inv (x , xs) = x ◂ xs chain-iso .rightInv _ = refl chain-iso .leftInv x i .head = x .head chain-iso .leftInv x i .tail = x .tail open import Data.Maybe.Properties module _ (isSetS : isSet S) (isSetA : isSet A) where isSetChain⁺′ : isSet (Chain⁺′ A) isSetChain⁺′ = isSetΣ (isSetΠ (λ _ → isOfHLevelMaybe 0 (isSet× isSetS isSetA))) λ f → isProp→isSet (isProp-final f) isSetChain : isSet (Chain A) isSetChain = subst isSet (isoToPath (sym-⇔ chain-iso)) (isSet× isSetA (subst isSet (isoToPath (sym-⇔ chain⁺-iso)) isSetChain⁺′))