-- * Prelude
module InductionFromFold where
open import Function
open import Data.Unit
open import Data.Empty
open import Data.Sum
open import Data.Product
open import Data.Nat
open import Relation.Binary hiding (_⇒_)
open import Relation.Binary.PropositionalEquality
infixr 7 _⇒_
_⇒_ : {I : Set} → (I → Set) → (I → Set) → Set
A ⇒ B = {i : _} → A i → B i
-- Let's work in a sufficiently extensional type theory:
postulate 
  extensionality : {A : Set}{B : A → Set}{f g : (a : A) → B a} →
                   ((x : A) → (f x ≡ g x)) → (f ≡ g)
-- Indeed, the constructions in this paper are derived from viewing
-- least fixpoint as strong initial objects, while an intensional
-- setting only gives weak initials.
-- * W-types
-- For convenience, I'm going to work on a specific family of
-- functors: the polynomial functors, also known as
-- "containers". Their least fixpoint corresponds exactly to the
-- W-types of Martin-Lof.
-- Remark: containers are defined on any LCCC. Here, we are going to
-- work on Set, for simplicity. We could consider polynomial functors
-- between slices of Set, thus describing inductive *families*
-- (ie. indexed W-types). Or, if there is such a thing, the equivalent
-- in the homotopic framework.
-- ** Definition
-- Containers let us describe the so-called "signature functor" of our
-- datatype, ie. the set of operations and their arity.
record Cont : Set1 where
  field
    Shape : Set
    Pos : Shape → Set
open Cont
-- Its meaning is made clear through the semantics-giving extension
-- function below.
-- ** Extension of a container
-- The extension of a container computes the (strictly) positive
-- functor described by the container.
⟦_⟧ : Cont → Set → Set
⟦ φ ⟧ X = Σ[ s ∶ Shape φ ] ((p : Pos φ s) → X)
-- Hence the name polynomial functor: it's a sum indexed by Shape φ of monomials of
-- exponent P φ s.
-- Exercises: 
--   * Write the container representing Nat
--   * Write the container representing node-labelled binary trees
-- * Initial algebra semantics
-- ** External fixpoint
-- Being strictly positive, these functors admits an initial
-- algebra. Agda is very happy to notice it.
data μ (φ : Cont) : Set where
  con : (x : ⟦ φ ⟧ (μ φ)) → μ φ
-- Categorically, reading ⟦ φ ⟧ as a functor F, this is nothing but
-- that initial algebra: 
--
--     con : F (μ F) → μ F
-- Exercises:
--   * Take the fixpoint of Nat and binary trees 
--   * Check you've indeed described Nat and trees
--   * In particular, write their constructors and convince yourself
--     that they are the only constructors
-- *** Catamorphism: existence
-- Pursuing on the categorical analogy, the existence of the initial
-- algebra tells us that for any ⟦ φ ⟧-algebra (X, α : ⟦ φ ⟧ X → X),
-- there exists a (unique) morphism foldCont α from μ φ to X:
foldCont : {φ : Cont}{X : Set}
           (α : ⟦ φ ⟧ X → X) →
           μ φ → X
foldCont m (con (s , f)) = m (s , \p → foldCont m (f p))
-- Remark: in type theory, we have the existence of the morphism: we
-- build the damned thing. However, without extensionality, there is
-- no way to prove uniqueness. Our initial algebras are weak. In this
-- presentation we shall need unicity: we have therefore postulated
-- extensionality and the resulting construction is computationally
-- inert :-(
-- Exercise: 
--   * Implement addition of natural numbers using foldCont
-- *** Catamorphism: unicity
-- I'm not going to prove unicity per se (which would amount to prove
-- η for inductive elimination). Instead, I just need to prove that
-- foldCont con is equal to the identity (ie. η in the specific case
-- of the identity, in a sense).
fold∙con≡id : {φ : Cont} → (x : μ φ) → foldCont con x ≡ x
fold∙con≡id {φ} (con (sh , pos)) = cong (\p → con (sh , p)) 
                                      (extensionality (λ p → fold∙con≡id (pos p)))
-- * Induction
-- The material in this section is a mixture of Bart Jacobs' Yellow
-- Pages, Claudio Hermida's PhD thesis and, my favorite, Clément Fumex
-- PhD thesis. Clément is the one that explained these things to
-- me. Any mistake would be my original contribution.
-- I've tried to stick to the categorical terminology and notations, as
-- much as Agda would let me.
-- ** Comprehension
-- The comprehension takes a predicate P and make it a set, the
-- obvious way:
⟨_⟩ : {X : Set} → (P : X → Set) → Set
⟨_⟩ P = Σ[ x ∶ _ ] P x
-- ** Canonical lifting
-- The canonical lifting takes a functor on Set, here presented as a
-- container φ, and "lift" it as a functor on predicates,
-- ie. functions X → Set:
infix 70 _^_
_^_ : (φ : Cont){X : Set}(P : X → Set) → ⟦ φ ⟧ X → Set
(φ ^ P) (sh , pos) = (p : Pos φ sh) → P (pos p) 
-- Intuitively, for a predicate P, the lifting asks that all
-- sub-branches of the tree-like structure ⟦ φ ⟧ X satisfy the
-- predicate P. This is computing the good ol' induction hypothesis!
-- Exercises: 
--   * Compute the lifting for Nat and binary trees
--   * Verify that these are indeed the induction hypothesis
-- ** Induction, implemented by a fold
-- You might have seen it coming by now: we are going to obtain
-- induction by using the initial φ-algebras. To do so, from the
-- induction step α : φ^ P ⇒ P ∘ con, we define a φ-algebra:
-- 
--    ( ⟨ P ⟩, α^ : ⟦ φ ⟧ ⟨ P ⟩ → ⟨ P ⟩ )
--
-- As follow:
ind : {φ : Cont}
      (P : μ φ → Set)
      (α : φ ^ P ⇒ P ∘ con) →
      (x : μ φ) → ⟨ P ⟩
ind {φ} P α = foldCont {X = ⟨ P ⟩} α^
  where α^ : ⟦ φ ⟧ ⟨ P ⟩ → ⟨ P ⟩
        α^ (sh , pos) = (con (sh , proj₁ ∘ pos)) , α {sh , proj₁ ∘ pos} (proj₂ ∘ pos)
-- Recall that ⟨ P ⟩ is a pair of an X and a P-witness for that X: our
-- algebra thus computes the identity for the first element of that
-- pair, while unfolding the inductive step on the proof side. Doing
-- so, we *know* (because we defined it so) that the result ⟨ P ⟩ is a
-- proof of P for the x we started with.
-- Remark: I've used a slightly obscure syntax to denote the inductive
-- step α : φ ^ P ⇒ P ∘ con. Put explicitly, here is the beast:
--
--     α : {xs : ⟦ φ ⟧ (μ φ)} → φ^ P xs → P (con xs)
--
-- Intuitively, this functions is nothing but the traditional
-- inductive step: for an (here, implicit) object xs : ⟦ φ ⟧ (μ φ), we
-- are given φ^ P xs -- the induction hypothesis -- and we are asked
-- to prove P (con xs).
-- Exercise: 
--   * Unfold α on Nat and binary trees
--   * Check that these are indeed the good ol' inductive steps
-- ** Proof: the result of ind is a proof on the initial x:
-- To prove this, we proceed in two steps. First, we prove that the
-- first element of the computed pair is equal to the folding the
-- initial algebra:
proj₁∘ind≡fold∙con : {φ : Cont}
                     (P : μ φ → Set)
                     (α : φ ^ P ⇒ P ∘ con)
                     (x : μ φ) →  proj₁ (ind P α x) ≡ foldCont con x
proj₁∘ind≡fold∙con {φ} P α (con (sh , pos)) = 
      cong (\x → con (sh , x))
           (extensionality help)
  where help : (x : Pos φ sh) → 
               ((proj₁ (ind P α (pos x))) ≡ foldCont con (pos x))
        help x =  proj₁∘ind≡fold∙con P α (pos x)
-- The second step is then to prove by transitivity the desired
-- result: the first element of the pair is actually the one we start
-- with:
proj₁∘ind≡id : {φ : Cont}
               (P : μ φ → Set)
               (α : φ ^ P ⇒ P ∘ con)
               (x : μ φ) → proj₁ (ind P α x) ≡ x
proj₁∘ind≡id {φ} P α x = trans (proj₁∘ind≡fold∙con P α x) 
                               (fold∙con≡id x)
-- * Induction
-- So, what is induction? It's simply the second projection of ind!
inductionCont : {φ : Cont}
                (P : μ φ → Set)
                (α : φ ^ P ⇒ P ∘ con)
                (x : μ φ) → P x
inductionCont P α x = subst P 
                            (proj₁∘ind≡id P α x) 
                            (proj₂ (ind P α x))
-- Remark: to fix the type, we have to substitute by our
-- proofs. Sadly, our proofs are non canonical: they rely on the
-- extensionality axiom. Consequently, this definition is
-- computationally inert. That's why doing category theory in type
-- theory is rarely a good idea ;-)