Documentation

Cslib.Foundations.Control.Monad.Free.Effects

Free Monad #

This file defines several canonical instances on the free monad.

Main definitions #

Implementation #

To execute or interpret these computations, we provide two approaches:

  1. Hand-written interpreters (FreeState.run, FreeWriter.run, FreeCont.run, FreeReader.run) that directly pattern-match on the tree structure
  2. Canonical interpreters (FreeState.toStateM, FreeWriter.toWriterT, FreeCont.toContT, FreeReader.toReaderM) derived from the universal property via liftM

We prove that these approaches are equivalent, demonstrating that the implementation aligns with the theory. We also provide uniqueness theorems for the canonical interpreters, which follow from the universal property.

Tags #

Free monad, state monad, writer monad, continuation monad

State Monad via FreeM #

inductive Cslib.FreeM.StateF (σ : Type u) :
Type u → Type u

Type constructor for state operations.

  • get {σ : Type u} : StateF σ σ

    Get the current state.

  • set {σ : Type u} : σStateF σ PUnit.{u + 1}

    Set the state.

Instances For
    @[reducible, inline]
    abbrev Cslib.FreeM.FreeState (σ : Type u) (α : Type u_1) :
    Type (max (u + 1) u_1)

    State monad via the FreeM monad.

    Equations
    Instances For
      @[implicit_reducible]
      instance Cslib.FreeM.FreeState.instMonadStateOf {σ : Type u} :
      MonadStateOf σ (FreeState σ)
      Equations
      • One or more equations did not get rendered due to their size.
      @[simp]
      theorem Cslib.FreeM.FreeState.set_def {σ : Type u} (s : σ) :
      set s = lift (StateF.set s)
      def Cslib.FreeM.FreeState.stateInterp {σ α : Type u} :
      StateF σ αStateM σ α

      Interpret StateF operations into StateM.

      Equations
      Instances For
        def Cslib.FreeM.FreeState.toStateM {σ α : Type u} (comp : FreeState σ α) :
        StateM σ α

        Convert a FreeState computation into a StateM computation. This is the canonical interpreter derived from liftM.

        Equations
        Instances For
          theorem Cslib.FreeM.FreeState.toStateM_unique {σ α : Type u} (g : FreeState σ αStateM σ α) (h : Interprets (fun {ι : Type u} => stateInterp) g) :

          toStateM is the unique interpreter extending stateInterp.

          def Cslib.FreeM.FreeState.run {σ : Type u} {α : Type v} (comp : FreeState σ α) (s₀ : σ) :
          α × σ

          Run a state computation, returning both the result and final state.

          Equations
          Instances For
            @[simp]
            theorem Cslib.FreeM.FreeState.run_toStateM {σ α : Type u} (comp : FreeState σ α) :
            StateT.run comp.toStateM = comp.run

            The canonical interpreter toStateM derived from liftM agrees with the hand-written recursive interpreter run for FreeState.

            @[simp]
            theorem Cslib.FreeM.FreeState.run_pure {σ : Type u} {α : Type v} (a : α) (s₀ : σ) :
            run (FreeM.pure a) s₀ = (a, s₀)
            @[simp]
            theorem Cslib.FreeM.FreeState.run_get {σ : Type u} {α : Type v} (k : σFreeState σ α) (s₀ : σ) :
            run (liftBind StateF.get k) s₀ = (k s₀).run s₀
            @[simp]
            theorem Cslib.FreeM.FreeState.run_set {σ : Type u} {α : Type v} (s' : σ) (k : PUnit.{u + 1}FreeState σ α) (s₀ : σ) :
            run (liftBind (StateF.set s') k) s₀ = (k PUnit.unit).run s'
            def Cslib.FreeM.FreeState.run' {σ : Type u} {α : Type v} (c : FreeState σ α) (s₀ : σ) :
            α

            Run a state computation, returning only the result.

            Equations
            Instances For
              @[simp]
              theorem Cslib.FreeM.FreeState.run'_toStateM {σ α : Type u} (comp : FreeState σ α) :
              StateT.run' comp.toStateM = comp.run'
              @[simp]
              theorem Cslib.FreeM.FreeState.run'_pure {σ : Type u} {α : Type v} (a : α) (s₀ : σ) :
              run' (FreeM.pure a) s₀ = a
              @[simp]
              theorem Cslib.FreeM.FreeState.run'_get {σ : Type u} {α : Type v} (k : σFreeState σ α) (s₀ : σ) :
              run' (liftBind StateF.get k) s₀ = (k s₀).run' s₀
              @[simp]
              theorem Cslib.FreeM.FreeState.run'_set {σ : Type u} {α : Type v} (s' : σ) (k : PUnit.{u + 1}FreeState σ α) (s₀ : σ) :
              run' (liftBind (StateF.set s') k) s₀ = (k PUnit.unit).run' s'

              Writer Monad via FreeM #

              inductive Cslib.FreeM.WriterF (ω : Type u) :
              Type v → Type u

              Type constructor for writer operations. Writer has a single effect, so the definition has just one constructor.

              • tell {ω : Type u} : ωWriterF ω PUnit.{v + 1}

                Write a value to the log.

              Instances For
                @[reducible, inline]
                abbrev Cslib.FreeM.FreeWriter (ω : Type u) (α : Type u_1) :
                Type (max (max (u_2 + 1) u) u_1)

                Writer monad implemented via the FreeM monad construction. This provides a more efficient implementation than the traditional WriterT transformer, as it avoids buffering the log.

                Equations
                Instances For
                  def Cslib.FreeM.FreeWriter.writerInterp {ω α : Type u} :
                  WriterF ω αWriterT ω Id α

                  Interpret WriterF operations into WriterT.

                  Equations
                  Instances For
                    def Cslib.FreeM.FreeWriter.toWriterT {ω α : Type u} [Monoid ω] (comp : FreeWriter ω α) :
                    WriterT ω Id α

                    Convert a FreeWriter computation into a WriterT computation. This is the canonical interpreter derived from liftM.

                    Equations
                    Instances For
                      theorem Cslib.FreeM.FreeWriter.toWriterT_unique {ω α : Type u} [Monoid ω] (g : FreeWriter ω αWriterT ω Id α) (h : Interprets (fun {ι : Type u} => writerInterp) g) :

                      toWriterT is the unique interpreter extending writerInterp.

                      @[reducible, inline]
                      abbrev Cslib.FreeM.FreeWriter.tell {ω : Type u} (w : ω) :
                      FreeWriter ω PUnit.{u_1 + 1}

                      Writes a log entry. This creates an effectful node in the computation tree.

                      Equations
                      Instances For
                        def Cslib.FreeM.FreeWriter.run {ω α : Type u} [Monoid ω] :
                        FreeWriter ω αα × ω

                        Interprets a FreeWriter computation by recursively traversing the tree, accumulating log entries with the monoid operation, and returns the final value paired with the accumulated log.

                        Equations
                        Instances For
                          @[simp]
                          theorem Cslib.FreeM.FreeWriter.run_pure {ω α : Type u} [Monoid ω] (a : α) :
                          run (FreeM.pure a) = (a, 1)
                          @[simp]
                          theorem Cslib.FreeM.FreeWriter.run_liftBind_tell {ω α : Type u} [Monoid ω] (w : ω) (k : PUnit.{u_1 + 1}FreeWriter ω α) :
                          run (liftBind (WriterF.tell w) k) = match (k PUnit.unit).run with | (a, w') => (a, w * w')
                          @[simp]
                          theorem Cslib.FreeM.FreeWriter.run_toWriterT {ω α : Type u} [Monoid ω] (comp : FreeWriter ω α) :
                          comp.toWriterT.run = comp.run

                          The canonical interpreter toWriterT derived from liftM agrees with the hand-written recursive interpreter run for FreeWriter.

                          def Cslib.FreeM.FreeWriter.listen {ω α : Type u} [Monoid ω] :
                          FreeWriter ω αFreeWriter ω (α × ω)

                          listen captures the log produced by a subcomputation incrementally. It traverses the computation, emitting log entries as encountered, and returns the accumulated log as a result.

                          Equations
                          Instances For
                            @[simp]
                            theorem Cslib.FreeM.FreeWriter.listen_pure {ω α : Type u} [Monoid ω] (a : α) :
                            @[simp]
                            theorem Cslib.FreeM.FreeWriter.listen_liftBind_tell {ω α : Type u} [Monoid ω] (w : ω) (k : PUnit.{u_1 + 1}FreeWriter ω α) :
                            listen (liftBind (WriterF.tell w) k) = liftBind (WriterF.tell w) fun (x : PUnit.{u_2 + 1}) => do let x(k PUnit.unit).listen match x with | (a, w') => pure (a, w * w')
                            def Cslib.FreeM.FreeWriter.pass {ω α : Type u} [Monoid ω] (m : FreeWriter ω (α × (ωω))) :

                            pass allows a subcomputation to modify its own log. After traversing the computation and accumulating its log, the resulting function is applied to rewrite the accumulated log before re-emission.

                            Equations
                            Instances For
                              @[simp]
                              theorem Cslib.FreeM.FreeWriter.pass_def {ω α : Type u} [Monoid ω] (m : FreeWriter ω (α × (ωω))) :
                              m.pass = match m.run with | ((a, f), w) => liftBind (WriterF.tell (f w)) fun (x : PUnit.{u_2 + 1}) => FreeM.pure a
                              @[implicit_reducible]
                              instance Cslib.FreeM.FreeWriter.instMonadWriterOfMonoid {ω : Type u} [Monoid ω] :
                              MonadWriter ω (FreeWriter ω)
                              Equations
                              • One or more equations did not get rendered due to their size.

                              Continuation Monad via FreeM #

                              inductive Cslib.FreeM.ContF (r : Type u) (α : Type v) :
                              Type (max u v)

                              Type constructor for continuation operations.

                              • callCC {r : Type u} {α : Type v} : ((αr)r)ContF r α

                                Call with current continuation: provides access to the current continuation.

                              Instances For
                                @[implicit_reducible]
                                instance Cslib.FreeM.instFunctorContF {r : Type u} :
                                Functor (ContF r)
                                Equations
                                • One or more equations did not get rendered due to their size.
                                @[reducible, inline]
                                abbrev Cslib.FreeM.FreeCont (r : Type u) (α : Type u_1) :
                                Type (max (max (u_2 + 1) u_2 u) u_1)

                                Continuation monad via the FreeM monad.

                                Equations
                                Instances For
                                  def Cslib.FreeM.FreeCont.contInterp {r : Type u} {α : Type v} :
                                  ContF r αContT r Id α

                                  Interpret ContF r operations into ContT r Id.

                                  Equations
                                  Instances For
                                    def Cslib.FreeM.FreeCont.toContT {r α : Type u} (comp : FreeCont r α) :
                                    ContT r Id α

                                    Convert a FreeCont computation into a ContT computation. This is the canonical interpreter derived from liftM.

                                    Equations
                                    Instances For
                                      theorem Cslib.FreeM.FreeCont.toContT_unique {r α : Type u} (g : FreeCont r αContT r Id α) (h : Interprets (fun {ι : Type u} => contInterp) g) :

                                      toContT is the unique interpreter extending contInterp.

                                      def Cslib.FreeM.FreeCont.run {r : Type u} {α : Type v} :
                                      FreeCont r α(αr)r

                                      Run a continuation computation with the given continuation.

                                      Equations
                                      Instances For
                                        @[simp]
                                        theorem Cslib.FreeM.FreeCont.run_toContT {r α : Type u} (comp : FreeCont r α) :
                                        comp.toContT.run = comp.run

                                        The canonical interpreter toContT derived from liftM agrees with the hand-written recursive interpreter run for FreeCont.

                                        @[simp]
                                        theorem Cslib.FreeM.FreeCont.run_pure {r : Type u} {α : Type v} (a : α) (k : αr) :
                                        run (FreeM.pure a) k = k a
                                        @[simp]
                                        theorem Cslib.FreeM.FreeCont.run_liftBind_callCC {r : Type u} {α : Type v} {β : Type w} (g : (αr)r) (cont : αFreeCont r β) (k : βr) :
                                        run (liftBind (ContF.callCC g) cont) k = g fun (a : α) => (cont a).run k
                                        def Cslib.FreeM.FreeCont.callCC {r : Type u} {α : Type v} {β : Type w} (f : MonadCont.Label α (FreeCont r) βFreeCont r α) :

                                        Call with current continuation for the Free continuation monad.

                                        Equations
                                        • One or more equations did not get rendered due to their size.
                                        Instances For
                                          @[simp]
                                          theorem Cslib.FreeM.FreeCont.callCC_def {r : Type u} {α : Type v} {β : Type w} (f : MonadCont.Label α (FreeCont r) βFreeCont r α) :
                                          callCC f = liftBind (ContF.callCC fun (k : αr) => (f { apply := fun (x : α) => liftBind (ContF.callCC fun (x_1 : βr) => k x) pure }).run k) pure
                                          @[implicit_reducible]
                                          instance Cslib.FreeM.FreeCont.instMonadCont {r : Type u} :
                                          MonadCont (FreeCont r)
                                          Equations
                                          @[simp]
                                          theorem Cslib.FreeM.FreeCont.run_callCC {r : Type u} {α : Type v} {β : Type w} (f : MonadCont.Label α (FreeCont r) βFreeCont r α) (k : αr) :
                                          (callCC f).run k = (f { apply := fun (x : α) => liftBind (ContF.callCC fun (x_1 : βr) => k x) pure }).run k

                                          run of a callCC node simplifies to running the handler with the current continuation.

                                          inductive Cslib.FreeM.ReaderF (σ : Type u) :
                                          Type u → Type u

                                          Type constructor for reader operations.

                                          Instances For
                                            @[reducible, inline]
                                            abbrev Cslib.FreeM.FreeReader (σ : Type u_1) (α : Type u_2) :
                                            Type (max (u_1 + 1) u_2)

                                            Reader monad via the FreeM monad

                                            Equations
                                            Instances For
                                              @[implicit_reducible]
                                              instance Cslib.FreeM.FreeReader.instMonadReader {σ : Type u} :
                                              MonadReader σ (FreeReader σ)
                                              Equations
                                              def Cslib.FreeM.FreeReader.readInterp {σ α : Type u} :
                                              ReaderF σ αReaderM σ α

                                              Interpret ReaderF operations into ReaderM.

                                              Equations
                                              Instances For
                                                def Cslib.FreeM.FreeReader.toReaderM {σ α : Type u} (comp : FreeReader σ α) :
                                                ReaderM σ α

                                                Convert a FreeReader computation into a ReaderM computation. This is the canonical interpreter derived from liftM.

                                                Equations
                                                Instances For
                                                  theorem Cslib.FreeM.FreeReader.toReaderM_unique {σ α : Type u} (g : FreeReader σ αReaderM σ α) (h : Interprets (fun {ι : Type u} => readInterp) g) :

                                                  toReaderM is the unique interpreter extending readInterp.

                                                  def Cslib.FreeM.FreeReader.run {σ α : Type u} (comp : FreeReader σ α) (s₀ : σ) :
                                                  α

                                                  Run a reader computation

                                                  Equations
                                                  Instances For
                                                    @[simp]
                                                    theorem Cslib.FreeM.FreeReader.run_toReaderM {σ α : Type u} (comp : FreeReader σ α) (s : σ) :
                                                    ReaderT.run comp.toReaderM s = comp.run s

                                                    The canonical interpreter toReaderM derived from liftM agrees with the hand-written recursive interpreter run for FreeReader

                                                    @[simp]
                                                    theorem Cslib.FreeM.FreeReader.run_pure {σ α : Type u} (a : α) (s₀ : σ) :
                                                    run (FreeM.pure a) s₀ = a
                                                    @[simp]
                                                    theorem Cslib.FreeM.FreeReader.run_read {σ α : Type u} (k : σFreeReader σ α) (s₀ : σ) :
                                                    run (liftBind ReaderF.read k) s₀ = (k s₀).run s₀
                                                    @[implicit_reducible]
                                                    instance Cslib.FreeM.FreeReader.instMonadWithReaderOf {σ : Type u} :
                                                    MonadWithReaderOf σ (FreeReader σ)
                                                    Equations
                                                    def Cslib.FreeM.FreeReader.instMonadWithReaderOf.go {σ α : Type u} (f : σσ) :
                                                    FreeReader σ αFreeReader σ α
                                                    Equations
                                                    Instances For
                                                      @[simp]
                                                      theorem Cslib.FreeM.FreeReader.run_withReader {σ α : Type u} (f : σσ) (m : FreeReader σ α) (s : σ) :
                                                      (withTheReader σ f m).run s = m.run (f s)