mirror of
https://github.com/dhil/phd-dissertation
synced 2026-03-13 02:58:26 +00:00
Free monad section
This commit is contained in:
@@ -1553,6 +1553,15 @@
|
|||||||
year = {1996}
|
year = {1996}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@inproceedings{Filinski99,
|
||||||
|
author = {Andrzej Filinski},
|
||||||
|
title = {Representing Layered Monads},
|
||||||
|
booktitle = {{POPL}},
|
||||||
|
pages = {175--188},
|
||||||
|
publisher = {{ACM}},
|
||||||
|
year = {1999}
|
||||||
|
}
|
||||||
|
|
||||||
# Landin's J operator
|
# Landin's J operator
|
||||||
@article{Landin65,
|
@article{Landin65,
|
||||||
author = {Peter J. Landin},
|
author = {Peter J. Landin},
|
||||||
|
|||||||
127
thesis.tex
127
thesis.tex
@@ -785,7 +785,13 @@ Haskell~\cite{JonesABBBFHHHHJJLMPRRW99}.
|
|||||||
\end{reductions}
|
\end{reductions}
|
||||||
\end{definition}
|
\end{definition}
|
||||||
%
|
%
|
||||||
\dhil{Remark that the monad type $T~A$ may be read as a tainted value}
|
We may understand the type $T~A$ as inhabiting computations that
|
||||||
|
compute a \emph{tainted} value of type $A$. In this regard, we may
|
||||||
|
understand $T$ as denoting the taint involved in computing $A$,
|
||||||
|
i.e. we can think of $T$ as sort of effect annotation which informs us
|
||||||
|
about which effectful operations the computation may perform to
|
||||||
|
produce $A$.
|
||||||
|
%
|
||||||
The monad interface may be instantiated in different ways to realise
|
The monad interface may be instantiated in different ways to realise
|
||||||
different computational effects. In the following subsections we will
|
different computational effects. In the following subsections we will
|
||||||
see three different instantiations with which we will implement global
|
see three different instantiations with which we will implement global
|
||||||
@@ -964,7 +970,15 @@ As in J.R.R. Tolkien's fictitious Middle-earth~\cite{Tolkien54} there
|
|||||||
exists one monad to rule them all, one monad to realise them, one
|
exists one monad to rule them all, one monad to realise them, one
|
||||||
monad to subsume them all, and in the term language bind them. This
|
monad to subsume them all, and in the term language bind them. This
|
||||||
powerful monad is the \emph{continuation monad}.
|
powerful monad is the \emph{continuation monad}.
|
||||||
%
|
|
||||||
|
The continuation monad may be regarded as `the universal effect' as it
|
||||||
|
can simulate any other computational effect~\cite{Filinski99}. It
|
||||||
|
derives its name from its connection to continuation passing
|
||||||
|
style~\cite{Wadler92}, which is a particular style of programming
|
||||||
|
where each function is parameterised by the current continuation (we
|
||||||
|
will discuss continuation passing style in detail in
|
||||||
|
Chapter~\ref{ch:cps}). The continuation monad is powerful exactly
|
||||||
|
because each of its operations has access to the current continuation.
|
||||||
|
|
||||||
|
|
||||||
\begin{definition}\label{def:cont-monad}
|
\begin{definition}\label{def:cont-monad}
|
||||||
@@ -982,7 +996,7 @@ powerful monad is the \emph{continuation monad}.
|
|||||||
\multirow{2}{*}{
|
\multirow{2}{*}{
|
||||||
\bl
|
\bl
|
||||||
\bind ~: T~A \to (A \to T~B) \to T~B\\
|
\bind ~: T~A \to (A \to T~B) \to T~B\\
|
||||||
\bind ~\defas \lambda m.\lambda k.\lambda f.m~(\lambda x.k~x~f)
|
\bind ~\defas \lambda m.\lambda k.\lambda c.m\,(\lambda x.k~x~c)
|
||||||
\el} \\ & % space hack to avoid the next paragraph from
|
\el} \\ & % space hack to avoid the next paragraph from
|
||||||
% floating into the math environment.
|
% floating into the math environment.
|
||||||
\ea
|
\ea
|
||||||
@@ -991,10 +1005,13 @@ powerful monad is the \emph{continuation monad}.
|
|||||||
\end{definition}
|
\end{definition}
|
||||||
%
|
%
|
||||||
The $\Return$ operation lifts a value into the monad by using it as an
|
The $\Return$ operation lifts a value into the monad by using it as an
|
||||||
argument to the continuation $k$. The bind operator applies the monad
|
argument to the continuation $k$. The bind operator binds the current
|
||||||
$m$ to an anonymous function that accepts a value $x$ of type
|
continuation to $c$. In the body it applies the monad $m$ to an
|
||||||
$A$. This value $x$ is supplied to the immediate continuation $k$
|
anonymous continuation function of type $A \to T~B$. Internally, the
|
||||||
alongside the current continuation $f$.
|
monad $m$ will apply this continuation when it is on the form
|
||||||
|
$\Return$. Thus the parameter $x$ gets bound to the $\Return$ value of
|
||||||
|
the monad. This parameter gets supplied as an argument to the next
|
||||||
|
monadic action $k$ alongside the current continuation $c$.
|
||||||
|
|
||||||
If we instantiate $R = S \to A \times S$ for some type $S$ then we
|
If we instantiate $R = S \to A \times S$ for some type $S$ then we
|
||||||
can implement the state monad inside the continuation monad.
|
can implement the state monad inside the continuation monad.
|
||||||
@@ -1041,14 +1058,18 @@ continuation.
|
|||||||
The initial continuation $(\lambda x.\lambda st. \Record{x;st})$
|
The initial continuation $(\lambda x.\lambda st. \Record{x;st})$
|
||||||
corresponds to the $\Return$ of the state monad.
|
corresponds to the $\Return$ of the state monad.
|
||||||
%
|
%
|
||||||
As usual by fixing $S = \Int$ and $A = \Bool$, we can use this
|
By fixing $S = \Int$ and $A = \Bool$, we can use the continuation
|
||||||
particular continuation monad instance to interpret $\incrEven$.
|
monad to interpret $\incrEven$.
|
||||||
%
|
%
|
||||||
\[
|
\[
|
||||||
\runState~\incrEven~4 \reducesto^+ \Record{\True;5} : \Bool \times \Int
|
\runState~\incrEven~4 \reducesto^+ \Record{\True;5} : \Bool \times \Int
|
||||||
\]
|
\]
|
||||||
%
|
%
|
||||||
|
The continuation monad gives us a succinct framework for implementing
|
||||||
|
and programming with computational effects, however, it comes at the
|
||||||
|
expense of extensibility and modularity. Adding a new operation to the
|
||||||
|
monad may require modifying its internal structure, which entails a
|
||||||
|
complete reimplementation of any existing operations.
|
||||||
% Scheme's undelimited control operator $\Callcc$ is definable as a
|
% Scheme's undelimited control operator $\Callcc$ is definable as a
|
||||||
% monadic operation on the continuation monad~\cite{Wadler92}.
|
% monadic operation on the continuation monad~\cite{Wadler92}.
|
||||||
% %
|
% %
|
||||||
@@ -1090,7 +1111,7 @@ the trivial continuation $\Unit$.
|
|||||||
|
|
||||||
The meaning of a free monadic computation is ascribed by a separate
|
The meaning of a free monadic computation is ascribed by a separate
|
||||||
function, or interpreter, that traverses the computation tree.
|
function, or interpreter, that traverses the computation tree.
|
||||||
|
%
|
||||||
The shape of computation trees is captured by the following generic
|
The shape of computation trees is captured by the following generic
|
||||||
type definition.
|
type definition.
|
||||||
%
|
%
|
||||||
@@ -1113,7 +1134,8 @@ operation is another computation tree node.
|
|||||||
$(F^{\TypeCat \to \TypeCat}, \Return, \bind)$ which forms a monad
|
$(F^{\TypeCat \to \TypeCat}, \Return, \bind)$ which forms a monad
|
||||||
with respect to $F$. In addition an adequate instance of $F$ must
|
with respect to $F$. In addition an adequate instance of $F$ must
|
||||||
supply a map, $\dec{fmap} : (A \to B) \to F~A \to F~B$, over its
|
supply a map, $\dec{fmap} : (A \to B) \to F~A \to F~B$, over its
|
||||||
structure.
|
structure (in more precise technical terms: $F$ must be a
|
||||||
|
\emph{functor}).
|
||||||
%
|
%
|
||||||
\[
|
\[
|
||||||
\bl
|
\bl
|
||||||
@@ -1137,6 +1159,17 @@ operation is another computation tree node.
|
|||||||
\el
|
\el
|
||||||
\]
|
\]
|
||||||
%
|
%
|
||||||
|
The $\Return$ operation simplify reflects itself by injecting the
|
||||||
|
value $x$ into the computation tree as a leaf node. The bind
|
||||||
|
operator threads the continuation $k$ through the computation
|
||||||
|
tree. Upon encounter a leaf node the continuation gets applied to
|
||||||
|
the value of the node. Note how this is reminiscent of the
|
||||||
|
$\Return$ of the continuation monad. The bind operator works in
|
||||||
|
tandem with the $\fmap$ of $F$ to advance past $\OpF$ nodes. The
|
||||||
|
$\fmap$ function is responsible for applying its functional
|
||||||
|
argument to the next computation tree node which is embedded inside
|
||||||
|
$y$.
|
||||||
|
%
|
||||||
We define an auxiliary function to alleviate some of the
|
We define an auxiliary function to alleviate some of the
|
||||||
boilerplate involved with performing operations on the monad.
|
boilerplate involved with performing operations on the monad.
|
||||||
%
|
%
|
||||||
@@ -1147,51 +1180,101 @@ operation is another computation tree node.
|
|||||||
\el
|
\el
|
||||||
\]
|
\]
|
||||||
%
|
%
|
||||||
|
This function injects some operation $op$ into the computation tree
|
||||||
|
as an operation node.
|
||||||
\end{definition}
|
\end{definition}
|
||||||
|
%
|
||||||
|
In order to implement state with the free monad we must first declare
|
||||||
|
a signature of its operations and implement the required $\fmap$ for
|
||||||
|
the signature.
|
||||||
|
%
|
||||||
\[
|
\[
|
||||||
\bl
|
\bl
|
||||||
\dec{FreeState}~S~R \defas [\Get:S \to R|\Put:\Record{S;R}] \smallskip\\
|
\FreeState~S~R \defas [\Get:S \to R|\Put:S \times (\UnitType \to R)] \smallskip\\
|
||||||
|
\fmap : (A \to B) \to \FreeState~S~A \to \FreeState~S~B\\
|
||||||
\fmap~f~op \defas \Case\;op\;\{
|
\fmap~f~op \defas \Case\;op\;\{
|
||||||
\ba[t]{@{}l@{~}c@{~}l}
|
\ba[t]{@{}l@{~}c@{~}l}
|
||||||
\Get~k &\mapsto& \Get\,(\lambda st.f\,(k~st));\\
|
\Get~k &\mapsto& \Get\,(\lambda st.f\,(k~st));\\
|
||||||
\Put~st~k &\mapsto& \Put\,\Record{st;f~k}\}
|
\Put\,\Record{st';k} &\mapsto& \Put\,\Record{st';\lambda\Unit.f\,(k\,\Unit)}\}
|
||||||
\ea
|
\ea
|
||||||
\el
|
\el
|
||||||
\]
|
\]
|
||||||
%
|
%
|
||||||
|
The signature $\FreeState$ declares the two stateful operations $\Get$
|
||||||
|
and $\Put$ over state type $S$ and continuation type $R$. The $\Get$
|
||||||
|
tag is parameterised a continuation function of type $S \to R$. The
|
||||||
|
idea is that an application of this function provides access to the
|
||||||
|
current state, whilst computing the next node of the computation
|
||||||
|
tree. The $\Put$ operation is parameterised by the new state value and
|
||||||
|
a thunk, which computes the next computation tree node. The $\fmap$
|
||||||
|
instance applies the function $f$ to the continuation $k$ of each
|
||||||
|
operation.
|
||||||
|
%
|
||||||
|
By instantiating $F = \FreeState\,S$ and using the $\DoF$ function we
|
||||||
|
can give the get and put operations a familiar look and feel.
|
||||||
|
%
|
||||||
\[
|
\[
|
||||||
\ba{@{~}l@{\qquad\quad}@{~}r}
|
\ba{@{~}l@{\qquad\quad}@{~}r}
|
||||||
\multirow{2}{*}{
|
\multirow{2}{*}{
|
||||||
\bl
|
\bl
|
||||||
\getF : \UnitType \to T~S\\
|
\getF : \UnitType \to T~S\\
|
||||||
\getF~\Unit \defas \DoF~(\Get\,(\lambda x.x))
|
\getF~\Unit \defas \DoF\,(\Get\,(\lambda st.st))
|
||||||
\el} &
|
\el} &
|
||||||
\multirow{2}{*}{
|
\multirow{2}{*}{
|
||||||
\bl
|
\bl
|
||||||
\putF : S \to T~\UnitType\\
|
\putF : S \to T~\UnitType\\
|
||||||
\putF~st \defas \DoF~(\Put\,\Record{st;\Unit})
|
\putF~st \defas \DoF\,(\Put\,\Record{st;\lambda\Unit.\Unit})
|
||||||
\el} \\ & % space hack to avoid the next paragraph from
|
\el} \\ & % space hack to avoid the next paragraph from
|
||||||
% floating into the math environment.
|
% floating into the math environment.
|
||||||
\ea
|
\ea
|
||||||
\]
|
\]
|
||||||
%
|
%
|
||||||
|
Both operations are performed with the identity function as their
|
||||||
|
respective continuation function. We do not have much choice in this
|
||||||
|
regard as for instance in the case of $\getF$ we must ultimately
|
||||||
|
return a computation of type $T~S$, and the only value of type $S$ we
|
||||||
|
have access to in this context is the one supplied externally to the
|
||||||
|
continuation function.
|
||||||
|
|
||||||
|
The state initialiser and runner for the monad is an interpreter. As
|
||||||
|
the programmers, we are free to choose whatever interpretation of
|
||||||
|
state we desire. For example, the following interprets the stateful
|
||||||
|
operations using the state-passing technique.
|
||||||
|
%
|
||||||
\[
|
\[
|
||||||
\bl
|
\bl
|
||||||
\runState : \Free\,(\dec{FreeState}~S)\,A \to S \to A \times S\\
|
\runState : (\UnitType \to \Free\,(\FreeState~S)\,A) \to S \to A \times S\\
|
||||||
\runState~m~st \defas
|
\runState~m~st \defas
|
||||||
\Case\;m\;\{
|
\Case\;m\,\Unit\;\{
|
||||||
\ba[t]{@{~}l@{~}c@{~}l}
|
\ba[t]{@{}l@{~}c@{~}l}
|
||||||
\return~x &\mapsto& (x, st);\\
|
\return~x &\mapsto& (x, st);\\
|
||||||
\OpF\,(\Get~k) &\mapsto& \runState~st~(k~st);\\
|
\OpF\,(\Get~k) &\mapsto& \runState~st~(\lambda\Unit.k~st);\\
|
||||||
\OpF\,(\Put\,\Record{st';k}) &\mapsto& \runState~st'~k
|
\OpF\,(\Put\,\Record{st';k}) &\mapsto& \runState~st'~k
|
||||||
\}\ea
|
\}\ea
|
||||||
\el
|
\el
|
||||||
\]
|
\]
|
||||||
%
|
%
|
||||||
|
The interpreter pattern matches on the shape of the monad (or
|
||||||
|
equivalently computation tree). In the case of a $\Return$ node the
|
||||||
|
interpreter returns the payload $x$ along with the final state value
|
||||||
|
$st$. If the current node is a $\Get$ operation, then the interpreter
|
||||||
|
recursively calls itself with the same state value $st$ and a thunked
|
||||||
|
application of the continuation $k$ to the current state $st$. The
|
||||||
|
recursive activation of $\runState$ will force the thunk in order to
|
||||||
|
compute the next computation tree node. In the case of a $\Put$
|
||||||
|
operation the interpreter calls itself recursively with new state
|
||||||
|
value $st'$ and the continuation $k$ (which is a thunk).
|
||||||
|
%
|
||||||
|
|
||||||
|
By instantiating $S = \Int$ we can use this interpreter to run
|
||||||
|
$\incrEven$.
|
||||||
|
%
|
||||||
\[
|
\[
|
||||||
\runState~4~(\incrEven~\Unit) \reducesto^+ \Record{\True;5}
|
\runState~\incrEven~4 \reducesto^+ \Record{\True;5} : \Bool \times \Int
|
||||||
\]
|
\]
|
||||||
|
%
|
||||||
|
The free monad brings us close to the essence of programming with
|
||||||
|
effect handlers.
|
||||||
|
|
||||||
\subsection{Back to direct-style}
|
\subsection{Back to direct-style}
|
||||||
Combining monadic effects~\cite{VazouL16}\dots
|
Combining monadic effects~\cite{VazouL16}\dots
|
||||||
|
|||||||
Reference in New Issue
Block a user