1
0
mirror of https://github.com/dhil/phd-dissertation synced 2026-04-28 15:06:29 +01:00

Compare commits

..

3 Commits

Author SHA1 Message Date
a46e2fd5d6 WIP 2021-05-19 18:11:36 +01:00
4ece98ba21 State example with delimited control 2021-05-19 17:49:50 +01:00
a609ca4b81 WIP 2021-05-19 11:16:22 +01:00
3 changed files with 266 additions and 29 deletions

View File

@@ -77,7 +77,8 @@
\newcommand{\Inl}{\keyw{inl}}
\newcommand{\Inr}{\keyw{inr}}
\newcommand{\Thunk}{\lambda \Unit.}
\newcommand{\PCFRef}{\keyw{ref}}
\newcommand{\PCFRef}{\dec{Ref}}
\newcommand{\refv}{\keyw{ref}}
\newcommand{\Pre}[1]{\mathsf{Pre}(#1)}
\newcommand{\Abs}{\mathsf{Abs}}

View File

@@ -822,6 +822,18 @@
year = {2012}
}
@inproceedings{VazouL16,
author = {Niki Vazou and
Daan Leijen},
title = {From Monads to Effects and Back},
booktitle = {{PADL}},
series = {{LNCS}},
volume = {9585},
pages = {169--186},
publisher = {Springer},
year = {2016}
}
@inproceedings{PauwelsSM19,
author = {Koen Pauwels and
Tom Schrijvers and
@@ -1517,7 +1529,7 @@
year = {1994}
}
# Simulation of delimited control using undelimited control
# Simulation of delimited control using undelimited control & monadic reflection
@inproceedings{Filinski94,
author = {Andrzej Filinski},
title = {Representing Monads},
@@ -1527,6 +1539,13 @@
year = {1994}
}
@phdthesis{Filinski96,
author = {Andrzej Filinski},
title = {Controlling Effects},
school = {Carnegie Mellon University},
year = {1996}
}
# Landin's J operator
@article{Landin65,
author = {Peter J. Landin},
@@ -3247,4 +3266,4 @@
number = {1},
pages = {1--32},
year = {2003}
}
}

View File

@@ -434,6 +434,195 @@ concerned with each time period.
\subsection{Early days of direct-style}
It is well-known that $\Callcc$ exhibits both time and space
performance problems for various implementing various
effects~\cite{Kiselyov12}.
%
\subsubsection{Builtin mutable state}
Builtin mutable state comes with three operations.
%
\[
\refv : S \to \PCFRef~S \qquad\quad
! : \PCFRef~S \to S \qquad\quad
\defnas~ : \PCFRef \to S \to \Unit
\]
%
The first operation \emph{initialises} a new mutable state cell; the
second operation \emph{gets} the value of a given state cell; and the
third operation \emph{puts} a new value into a given state cell. It is
important to note here retrieving contents of the state cell is an
idempotent action, whilst modifying the contents is a destructive
action.
The following function illustrates a use of the get and put primitives
to manipulate the contents of some global state cell $st$.
%
\[
\bl
\incrEven : \UnitType \to \Bool\\
\incrEven\,\Unit \defas \Let\;v \revto !st\;\In\;st \defnas 1 + v\;\In\;\even~st
\el
\]
%
The type signature is oblivious to the fact that the function
internally makes use of the state effect to compute its return value.
%
We can run this computation as a subcomputation in the context of
global state cell $st$.
%
\[
\Let\;st \revto \refv~4\;\In\;\Record{\incrEven\,\Unit;!st} \reducesto^+ \Record{\True;5} : \Bool \times \Int
\]
%
Operationally, the whole computation initialises the state cell $st$
to contain the integer value $4$. Subsequently it runs the $\incrEven$
computation, which returns the boolean value $\True$ and as a
side-effect increments the value of $st$ to be $5$. The whole
computation returns the boolean value paired with the final value of
the state cell.
\subsubsection{Transparent state-passing purely functionally}
%
\[
\bl
\incrEven : \UnitType \to \Int \to \Bool \times \Int\\
\incrEven\,\Unit \defas \lambda st. \Record{\even~st; 1 + st}
\el
\]
%
State-passing is a global phenomenon that requires us to rewrite the
signatures (and their implementations) of all functions that makes use
of state, i.e. in order to endow an $n$-ary function that returns some
value of type $R$ with state $S$ we have to transform its type as
follows.
%
\[
\val{A_1 \to \cdots \to A_n \to R}_S
= A_0 \to \cdots \to A_n \to S \to R \times S
\]
%
\subsubsection{Opaque state-passing with delimited control}
%
Delimited control appears during the late 80s in different
forms~\cite{SitaramF90,DanvyF89}.
%
There are several different forms of delimited control. The
particular form of delimited control that I will use here is due to
\citet{DanvyF89}.
%
Nevertheless, the secret sauce of all forms of delimited control is
that a delimited control operator makes it possible to pry open
function boundaries as control may transfer out of an arbitrary
evaluation context, leaving behind a hole that can later be filled by
some value supplied externally.
\citeauthor{DanvyF89}'s formulation of delimited control introduces
the following two primitives.
%
\[
\reset{-} : (\UnitType \to R) \to R \qquad\quad
\shift : ((A \to R) \to R) \to A
\]
%
The first primitive $\reset{-}$ (pronounced `reset') is a control
delimiter. Operationally, reset evaluates a given thunk in an empty
evaluation context and returns the final result of that evaluation.
%
The second primitive $\shift$ is a control reifier. An application
$\shift$ reifies and erases the control state up to (but not
including) the nearest enclosing reset. The reified control state
represents the continuation of the invocation of $\shift$ (up to the
innermost reset); it gets passed as a function to the argument of
$\shift$.
Both primitives are defined over some (globally) fixed result type
$R$.
%
By instantiating $R = S \to A \times S$, where $S$ is the type of
state and $A$ is the type of return values, then we can use shift and
reset to simulate mutable state using state-passing in way that is
opaque to the rest of the program.
%
Let us first define operations for accessing and modifying the state
cell.
%
\[
\ba{@{~}l@{\qquad\quad}@{~}r}
\multirow{2}{*}{
\bl
\getF : \UnitType \to S\\
\getF~\Unit \defas \shift\,(\lambda k.\lambda st. k~st~st)
\el} &
\multirow{2}{*}{
\bl
\putF : S \to \UnitType\\
\putF~st \defas \shift\,(\lambda k.\lambda st'.k~\Unit~st)
\el} \\ & % space hack to avoid the next paragraph from
% floating into the math environment.
\ea
\]
%
The body of $\getF$ applies $\shift$ to capture the current
continuation, which gets supplied to the anonymous function
$(\lambda k.\lambda st. k~st~st)$. The continuation parameter $k$ has
type $S \to S \to A \times S$. The continuation is applied to two
instances of the current state value $st$. The instance the value
returned to the caller of $\getF$, whilst the second instance is the
state value available during the next invocation of either $\getF$ or
$\putF$. This aligns with the intuition that accessing a state cell
does not modify its contents. The implementation of $\putF$ is
similar, except that the first argument to $k$ is the unit value,
because the caller of $\putF$ expects a unit in return. Also, it
ignores the current state value $st'$ and instead passes the state
argument $st$ onto the activation of the next state operation. Again,
this aligns with the intuition that modifying a state cell destroys
its previous contents.
Using these two operations we can implement a version of $\incrEven$
that takes advantage of delimited control to simulate global state.
%
\[
\bl
\incrEven : \UnitType \to \Bool\\
\incrEven\,\Unit \defas \Let\;st \revto \getF\,\Unit\;\In\;\putF\,(1 + st);\,\even~st
\el
\]
%
Modulo naming of operations, this version is similar to the version
that uses builtin state. The type signature of the function is even
the same.
%
Before we can apply this function we must first a state initialiser.
%
\[
\bl
\runState : (\UnitType \to A) \to S \to A \times S\\
\runState~m~st_0 \defas \reset{\lambda\Unit.\Let\;x \revto m\,\Unit\;\In\;\lambda st. \Record{x;st}}\,st_0
\bl
\el
\el
\]
%
The function $\runState$ acts as both the state cell initialiser and
runner of the stateful computation. The first parameter $m$ is a thunk
that may perform stateful operations and the second parameter $st_0$
is the initial value of the state cell. The implementation wraps an
instance of reset around the application of $m$ in order to delimit
the extent of applications of $\shift$ within $m$. It is important to
note that each invocation of $\getF$ and $\putF$ gives rise to a
state-accepting function, thus when $m$ is applied a chain of
state-accepting functions gets constructed lazily. The chain ends in
the state-accepting function returned by the reset instance. The
application of the reset instance to $st_0$ effectively causes
evaluation of each function in this chain to start.
After instantiating $A = \Bool$ and $S = \Int$ we can use the
$\runState$ function to apply the $\incrEven$ function.
%
\[
\runState~\incrEven~4~ \reducesto^+ \Record{\True;5} : \Bool \times \Int
\]
\subsection{Monadic epoch}
During the late 80s and early 90s monads rose to prominence as a
practical programming idiom for structuring effectful
@@ -454,10 +643,22 @@ In practical programming terms, monads may be thought of as
constituting a family of design patterns, where each pattern gives
rise to a distinct effect with its own operations.
%
The part of the appeal of monads is that they provide a structured
interface for programming with effects such as state, exceptions,
nondeterminism, and so forth, whilst preserving the equational style
of reasoning about pure functional
programs~\cite{GibbonsH11,Gibbons12}.
%
% Notably, they form the foundations for effectful programming in
% Haskell, which adds special language-level support for programming
% with monads~\cite{JonesABBBFHHHHJJLMPRRW99}.
%
The presentation of monads here is inspired by \citeauthor{Wadler92}'s
presentation of monads for functional programming~\cite{Wadler92}, and
it should be familiar to users of
Haskell~\cite{JonesABBBFHHHHJJLMPRRW99}.
\begin{definition}
A monad is a triple $(T^{\TypeCat \to \TypeCat}, \Return, \bind)$
where $T$ is some unary type constructor, $\Return$ is an operation
@@ -482,11 +683,12 @@ rise to a distinct effect with its own operations.
\end{reductions}
\end{definition}
%
Monads have a proven track record of successful applications.
The monad laws ensure that monads have some algebraic structure.
Monads have also given rise to various popular control-oriented
programming abstractions, e.g. the asynchronous programming idiom
async/await has its origins in monadic
The success of monads as a programming idiom is difficult to
understate as monads have given rise to several popular
control-oriented programming abstractions including the asynchronous
programming idiom async/await has its origins in monadic
programming~\cite{Claessen99,LiZ07,SymePL11}.
% \subsection{Option monad}
@@ -521,9 +723,10 @@ programming~\cite{Claessen99,LiZ07,SymePL11}.
\subsubsection{State monad}
%
The state monad encapsulates mutable state by using the state-passing
technique internally. It provides two operations for manipulating the
state cell.
The state monad is an instantiation of the monad interface that
encapsulates mutable state by using the state-passing technique
internally. In addition it equip the monad with two operations for
manipulating the state cell.
%
\begin{definition}\label{def:state-monad}
The state monad is defined over some fixed state type $S$.
@@ -595,8 +798,9 @@ The literature often presents the state monad with a fourth equation,
which states that $\getF$ is idempotent. However, this equation is
redundant as it is derivable from the first and third equations.
The following bit toggling function illustrates a use of the state
monad.
We can implement a monadic variation of the $\incrEven$ function that
uses the state monad to emulate manipulations of the state cell as
follows.
%
\[
\bl
@@ -622,15 +826,28 @@ $\even : \Int \to \Bool$ to the original state value to test whether
its parity is even. The structure of the monad means that the result
of running this computation gives us a pair consisting of boolean
value indicating whether the initial state was even and the final
state value. For instance, if the initial state value is $\True$, then
the computation yields
state value.
The state initialiser and monad runner is simply thunk forcing and
function application combined.
%
\[
\incrEven~\Unit~4 \reducesto^+ \Record{\True;5},
\bl
\runState : (\UnitType \to T~A) \to S \to A \to S\\
\runState~m~st_0 \defas m~\Unit~st_0\\
\el
\]
%
where the first component contains the initial state value and the
second component contains the final state value.
By instantiating $S = \Int$ and $A = \Bool$ we can obtain the same
result as before.
%
\[
\runState~\incrEven~4 \reducesto^+ \Record{\True;5} : \Bool \times \Int
\]
%
We can instantiate the monad structure in a similar way to simulate
other computational effects such as exceptions, nondeterminism,
concurrency, and so forth~\cite{Moggi91,Wadler92}.
\subsubsection{Continuation monad}
As in J.R.R. Tolkien's fictitious Middle-earth~\cite{Tolkien54} there
@@ -812,11 +1029,11 @@ operation is another computation tree node.
\[
\bl
\dec{FreeState}~S~R \defas [\Get:S \to R|\Put:\Record{S;R}] \smallskip\\
\fmap~f~x \defas \Case\;x\;\{
\bl
\Get~k \mapsto \Get\,(\lambda st.f\,(k~st));\\
\Put~st'~k \mapsto \Put\,\Record{st';f~k}\}
\el
\fmap~f~op \defas \Case\;op\;\{
\ba[t]{@{}l@{~}c@{~}l}
\Get~k &\mapsto& \Get\,(\lambda st.f\,(k~st));\\
\Put~st~k &\mapsto& \Put\,\Record{st;f~k}\}
\ea
\el
\]
%
@@ -838,8 +1055,8 @@ operation is another computation tree node.
%
\[
\bl
\runState : S \to \Free\,(\dec{FreeState}~S)\,A \to A \times S\\
\runState~st~m \defas
\runState : \Free\,(\dec{FreeState}~S)\,A \to S \to A \times S\\
\runState~m~st \defas
\Case\;m\;\{
\ba[t]{@{~}l@{~}c@{~}l}
\return~x &\mapsto& (x, st);\\
@@ -854,7 +1071,7 @@ operation is another computation tree node.
\]
\subsection{Back to direct-style}
Combining monadic effects~\cite{VazouL16}\dots
\subsubsection{Effect tracking}
@@ -1320,13 +1537,13 @@ distinct notions of continuations. It is common in the literature to
find the word `continuation' accompanied by a qualifier such as full,
partial, abortive, escape, undelimited, delimited, composable, or
functional (in Chapter~\ref{ch:cps} I will extend this list by three
new ones). Some of these notions of continuations synonyms, whereas
others have distinct meaning. Common to all notions of continuations
is that in essence they represent the control state. However, the
new ones). Some of these notions of continuations are synonymous,
whereas others have distinct meanings. Common to all notions of
continuations is that they represent the control state. However, the
extent and behaviour of continuations differ widely from notion to
notion. The essential notions of continuations are
undelimited/delimited and abortive/composable. To tell them apart, we
will classify them by their operational behaviour.
will classify them according to their operational behaviour.
The extent and behaviour of a continuation in programming are
determined by its introduction and elimination forms,