mirror of
https://github.com/dhil/phd-dissertation
synced 2026-03-13 02:58:26 +00:00
Chap 6 rewrite WIP
This commit is contained in:
25
macros.tex
25
macros.tex
@@ -465,3 +465,28 @@
|
|||||||
\newcommand{\Algol}{Algol~60}
|
\newcommand{\Algol}{Algol~60}
|
||||||
\newcommand{\qq}[1]{\ensuremath{\ulcorner #1 \urcorner}}
|
\newcommand{\qq}[1]{\ensuremath{\ulcorner #1 \urcorner}}
|
||||||
\newcommand{\prompttype}{\dec{Prompt}}
|
\newcommand{\prompttype}{\dec{Prompt}}
|
||||||
|
|
||||||
|
% Language macros
|
||||||
|
\newcommand{\Frank}{Frank}
|
||||||
|
\newcommand{\SML}{SML}
|
||||||
|
\newcommand{\SMLNJ}{\SML{}/NJ}
|
||||||
|
\newcommand{\OCaml}{OCaml}
|
||||||
|
|
||||||
|
|
||||||
|
% Tikz figures
|
||||||
|
\newcommand\toggle{
|
||||||
|
\begin{tikzpicture}[->,>=stealth',level/.style={sibling distance = 5cm/##1,
|
||||||
|
level distance = 1.5cm}]
|
||||||
|
\node [opnode] {$\Get~\Unit$}
|
||||||
|
child{ node [opnode] {$\Put~\False$}
|
||||||
|
child{ node [leaf] {$\True$}
|
||||||
|
edge from parent node[left] {$\Unit$}}
|
||||||
|
edge from parent node[above left] {$\True$}
|
||||||
|
}
|
||||||
|
child{ node [opnode] {$\Put~v$}
|
||||||
|
child{ node [leaf] {$\False$}
|
||||||
|
edge from parent node[right] {$\res{()}$}}
|
||||||
|
edge from parent node[above right] {$\res{\False}$}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
\end{tikzpicture}}
|
||||||
12
thesis.bib
12
thesis.bib
@@ -465,6 +465,18 @@
|
|||||||
year = {2017}
|
year = {2017}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@article{ConventLMM20,
|
||||||
|
author = {Lukas Convent and
|
||||||
|
Sam Lindley and
|
||||||
|
Conor McBride and
|
||||||
|
Craig McLaughlin},
|
||||||
|
title = {Doo bee doo bee doo},
|
||||||
|
journal = {J. Funct. Program.},
|
||||||
|
volume = {30},
|
||||||
|
pages = {e9},
|
||||||
|
year = {2020}
|
||||||
|
}
|
||||||
|
|
||||||
@MastersThesis{Convent17,
|
@MastersThesis{Convent17,
|
||||||
author = {Lukas Convent},
|
author = {Lukas Convent},
|
||||||
title = {Enhancing a Modular Effectful Programming Language},
|
title = {Enhancing a Modular Effectful Programming Language},
|
||||||
|
|||||||
199
thesis.tex
199
thesis.tex
@@ -4461,10 +4461,13 @@ to the operations.
|
|||||||
|
|
||||||
\subsection{Handling of effectful operations}
|
\subsection{Handling of effectful operations}
|
||||||
%
|
%
|
||||||
We now present the elimination form for effectful operations, namely,
|
The elimination form for an effectful operation is an effect
|
||||||
handlers.
|
handler. Effect handlers interpret the effectful segments of a
|
||||||
|
program.
|
||||||
%
|
%
|
||||||
First we define notation for handler kinds and types.
|
The addition of handlers requires us to extend the type algebra of
|
||||||
|
$\BCalc$ with a kind for handlers and a new syntactic category for
|
||||||
|
handler types.
|
||||||
%
|
%
|
||||||
\begin{syntax}
|
\begin{syntax}
|
||||||
\slab{Kinds} &K \in \KindCat &::=& \cdots \mid \Handler\\
|
\slab{Kinds} &K \in \KindCat &::=& \cdots \mid \Handler\\
|
||||||
@@ -4474,10 +4477,17 @@ First we define notation for handler kinds and types.
|
|||||||
%
|
%
|
||||||
The syntactic category of kinds is augmented with the kind $\Handler$
|
The syntactic category of kinds is augmented with the kind $\Handler$
|
||||||
which we will ascribe to handler types $F$. The arrow, $\Harrow$,
|
which we will ascribe to handler types $F$. The arrow, $\Harrow$,
|
||||||
denotes the handler space. Type structure suggests that a handler is a
|
denotes the handler space. The type structure suggests that a handler
|
||||||
transformer of computations, as by the types it takes a computation of
|
is a transformer of computations, since by looking solely at the types
|
||||||
type $C$ and returns another computation of type $D$. We use the
|
a handler takes a computation of type $C$ and returns another
|
||||||
following kinding rule to check that a handler type is well-kinded.
|
computation of type $D$. As such, we may think of a handler as a sort
|
||||||
|
of generalised function, that work over computations rather than bare
|
||||||
|
values (this observation is exploited in the \Frank{} programming
|
||||||
|
language, where a function is but a special case of a
|
||||||
|
handler~\cite{LindleyMM17,ConventLMM20}).
|
||||||
|
%
|
||||||
|
The following kinding rule checks whether a handler type is
|
||||||
|
well-kinded.
|
||||||
%
|
%
|
||||||
\begin{mathpar}
|
\begin{mathpar}
|
||||||
\inferrule*[Lab=\klab{Handler}]
|
\inferrule*[Lab=\klab{Handler}]
|
||||||
@@ -4487,10 +4497,10 @@ following kinding rule to check that a handler type is well-kinded.
|
|||||||
{\Delta \vdash C \Harrow D : \Handler}
|
{\Delta \vdash C \Harrow D : \Handler}
|
||||||
\end{mathpar}
|
\end{mathpar}
|
||||||
%
|
%
|
||||||
With the type structure in place, we present the term syntax for
|
With the type structure in place, we can move on to the term syntax
|
||||||
handlers. The addition of handlers augments the syntactic category of
|
for handlers. Handlers extend the syntactic category of computations
|
||||||
computations with a new computation form as well as introducing a new
|
with a new computation form as well as introducing a new syntactic
|
||||||
syntactic category of handler definitions.
|
category of handler definitions.
|
||||||
%
|
%
|
||||||
\begin{syntax}
|
\begin{syntax}
|
||||||
\slab{Computations} &M,N \in \CompCat &::=& \cdots \mid \Handle \; M \; \With \; H\\[1ex]
|
\slab{Computations} &M,N \in \CompCat &::=& \cdots \mid \Handle \; M \; \With \; H\\[1ex]
|
||||||
@@ -4506,15 +4516,19 @@ possibly empty set of operation clauses
|
|||||||
$\{\OpCase{\ell}{p_\ell}{r_\ell} \mapsto N_\ell\}_{\ell \in \mathcal{L}}$.
|
$\{\OpCase{\ell}{p_\ell}{r_\ell} \mapsto N_\ell\}_{\ell \in \mathcal{L}}$.
|
||||||
%
|
%
|
||||||
The return clause $\{\Return \; x \mapsto M\}$ defines how to
|
The return clause $\{\Return \; x \mapsto M\}$ defines how to
|
||||||
interpret the final return value of a handled computation. The
|
interpret the final return value of a handled computation, i.e. a
|
||||||
variable $x$ is bound to the final return value in the body $M$.
|
computation that has been fully reduced to $\Return~V$ for some value
|
||||||
|
$V$. The variable $x$ is bound to the final return value in the body
|
||||||
|
$M$.
|
||||||
%
|
%
|
||||||
Each operation clause
|
Each operation clause
|
||||||
$\{\OpCase{\ell}{p_\ell}{r_\ell} \mapsto N_\ell\}_{\ell \in \mathcal{L}}$
|
$\{\OpCase{\ell}{p_\ell}{r_\ell} \mapsto N_\ell\}_{\ell \in
|
||||||
defines how to interpret an invocation of a particular operation
|
\mathcal{L}}$ defines how to interpret an invocation of some
|
||||||
$\ell$. The variables $p_\ell$ and $r_\ell$ are bound in the body
|
operation $\ell$. The variables $p_\ell$ and $r_\ell$ are bound in the
|
||||||
$N_\ell$: $p_\ell$ binds the argument carried by the operation and
|
body $N_\ell$. The binding occurrence $p_\ell$ binds the payload of
|
||||||
$r_\ell$ binds the continuation of the invocation site of $\ell$.
|
the operation and $r_\ell$ binds the resumption of the operation
|
||||||
|
invocation, which is the delimited continuation from the invocation
|
||||||
|
site up of $\ell$ to and including the enclosing handler.
|
||||||
|
|
||||||
Given a handler $H$, we often wish to refer to the clause for a
|
Given a handler $H$, we often wish to refer to the clause for a
|
||||||
particular operation or the return clause; for these purposes we
|
particular operation or the return clause; for these purposes we
|
||||||
@@ -4541,8 +4555,9 @@ labels it handles, i.e.
|
|||||||
|
|
||||||
\subsection{Static semantics}
|
\subsection{Static semantics}
|
||||||
|
|
||||||
The typing of effect handlers is slightly more involved than the
|
There are two typing rules for handlers. The first rule type checks
|
||||||
typing of the $\Do$-construct.
|
the $\Handle$-construct and the second rule type checks handler
|
||||||
|
definitions.
|
||||||
%
|
%
|
||||||
\begin{mathpar}
|
\begin{mathpar}
|
||||||
\inferrule*[Lab=\tylab{Handle}]
|
\inferrule*[Lab=\tylab{Handle}]
|
||||||
@@ -4566,6 +4581,7 @@ typing of the $\Do$-construct.
|
|||||||
{\typ{\Delta;\Gamma}{H : C \Harrow D}}
|
{\typ{\Delta;\Gamma}{H : C \Harrow D}}
|
||||||
\end{mathpar}
|
\end{mathpar}
|
||||||
%
|
%
|
||||||
|
The \tylab{Handle} rule is simply the application rule for handlers.
|
||||||
%
|
%
|
||||||
The \tylab{Handler} rule is where most of the work happens. The effect
|
The \tylab{Handler} rule is where most of the work happens. The effect
|
||||||
rows on the input computation type $C$ and the output computation type
|
rows on the input computation type $C$ and the output computation type
|
||||||
@@ -4602,12 +4618,19 @@ for handling return values and another for handling operations.
|
|||||||
The rule \semlab{Ret} invokes the return clause of the current handler
|
The rule \semlab{Ret} invokes the return clause of the current handler
|
||||||
$H$ and substitutes $V$ for $x$ in the body $N$.
|
$H$ and substitutes $V$ for $x$ in the body $N$.
|
||||||
%
|
%
|
||||||
The rule \semlab{Op} handles an operation $\ell$, provided that the
|
The rule \semlab{Op} handles an operation $\ell$ subject to two
|
||||||
handler definition $H$ contains a corresponding operation clause for
|
conditions. The first condition ensures that the operation is only
|
||||||
$\ell$ and that $\ell$ does not appear in the \emph{bound labels}
|
captured by a handler if its handler definition $H$ contains a
|
||||||
($\BL$) of the inner context $\EC$. The bound label condition enforces
|
corresponding operation clause for the operation. Otherwise the
|
||||||
that an operation is always handled by the nearest enclosing suitable
|
operation passes seamlessly through the handler such that another
|
||||||
handler.
|
suitable handler can handle the operation. This phenomenon is known as
|
||||||
|
\emph{effect forwarding}. It is key to enable modular composition of
|
||||||
|
effectful computations.
|
||||||
|
%
|
||||||
|
The second condition ensures the operation $\ell$ and that the
|
||||||
|
operation does not appear in the \emph{bound labels} ($\BL$) of the
|
||||||
|
inner context $\EC$. The bound label condition enforces that an
|
||||||
|
operation is always handled by the nearest enclosing suitable handler.
|
||||||
%
|
%
|
||||||
Formally, we define the notion of bound labels,
|
Formally, we define the notion of bound labels,
|
||||||
$\BL : \EvalCat \to \LabelCat$, inductively over the structure of
|
$\BL : \EvalCat \to \LabelCat$, inductively over the structure of
|
||||||
@@ -4647,22 +4670,22 @@ because $\ell$ is bound in the computation term of the outermost
|
|||||||
$\Handle$.
|
$\Handle$.
|
||||||
%
|
%
|
||||||
|
|
||||||
We have made a conscious design decision by always selecting nearest
|
The decision to always select the nearest enclosing suitable handler
|
||||||
enclosing suitable handler for any operation. In fact, we have made
|
for an operation invocation is a conscious choice. In fact, it is the
|
||||||
the \emph{only} natural and sensible choice as picking any other
|
\emph{only} natural and sensible choice as picking any other handler
|
||||||
handler than the nearest enclosing renders programming with effect
|
than the nearest enclosing renders programming with effect handlers
|
||||||
handlers anti-modular. Consider always selecting the outermost
|
anti-modular. Consider the other extreme of always selecting the
|
||||||
suitable handler, then the meaning of closed program composition
|
outermost suitable handler, then the meaning of any effectful program
|
||||||
cannot be derived from its immediate constituents. For example,
|
fragment depends on the entire ambient context. For example, consider
|
||||||
consider using integer addition as the composition operator to compose
|
using integer addition as the composition operator to compose the
|
||||||
the inner handle expression from above with a copy of itself.
|
inner handle expression from above with a copy of itself.
|
||||||
%
|
%
|
||||||
\[
|
\[
|
||||||
\bl
|
\bl
|
||||||
\dec{fortytwo} \defas \Handle\;\Do\;\ell~\Unit\;\With\;H_{\mathsf{inner}} \medskip\\
|
\dec{fortytwo} \defas \Handle\;\Do\;\ell~\Unit\;\With\;H_{\mathsf{inner}} \medskip\\
|
||||||
\EC[\dec{fortytwo} + \dec{fortytwo}] \reducesto^+ \begin{cases}
|
\EC[\dec{fortytwo} + \dec{fortytwo}] \reducesto^+ \begin{cases}
|
||||||
\Return\; 84 & \text{when $\EC$ is empty}\\
|
\Return\; 84 & \text{when $\EC$ is empty}\\
|
||||||
?? & \text{otherwise}
|
? & \text{otherwise}
|
||||||
\end{cases}
|
\end{cases}
|
||||||
\el
|
\el
|
||||||
\]
|
\]
|
||||||
@@ -4670,17 +4693,21 @@ the inner handle expression from above with a copy of itself.
|
|||||||
Clearly, if the ambient context $\EC$ is empty, then we can derive the
|
Clearly, if the ambient context $\EC$ is empty, then we can derive the
|
||||||
result by reasoning locally about each constituent separately and
|
result by reasoning locally about each constituent separately and
|
||||||
subsequently add their results together to obtain the computation term
|
subsequently add their results together to obtain the computation term
|
||||||
$\Return\;84$. However, if the ambient context is nonempty, then we
|
$\Return\;84$. Conversely, if the ambient context is nonempty, then we
|
||||||
need to account for the possibility that some handler for $\ell$ could
|
need to account for the possibility that some handler for $\ell$ is
|
||||||
occur in the context. For instance if
|
could be present in the context. For instance if
|
||||||
$\EC = \Handle\;[~]\;\With\;H_{\mathsf{outer}}$ then the result would
|
$\EC = \Handle\;[~]\;\With\;H_{\mathsf{outer}}$ then the result would
|
||||||
be $\Return\;0$, which we cannot derive locally from looking at the
|
be $\Return\;0$, which we cannot derive locally from looking at the
|
||||||
constituents. Thus we argue that if we want programming to remain
|
immediate constituents. Thus we can argue that if we want programming
|
||||||
modular and compositional, then we must necessarily always select the
|
to remain modular and compositional, then we must necessarily always
|
||||||
nearest enclosing suitable handler to handle an operation invocation.
|
select the nearest enclosing suitable handler for an operation.
|
||||||
%
|
%
|
||||||
\dhil{Effect forwarding (the first condition)}
|
|
||||||
|
|
||||||
|
The resumption $r$ includes both the captured evaluation context and
|
||||||
|
the handler. Invoking the resumption causes the both the evaluation
|
||||||
|
context and handler to be reinstalled, meaning subsequent invocations
|
||||||
|
of $\ell$ get handled by the same handler. This is a defining
|
||||||
|
characteristic of deep handlers.
|
||||||
|
|
||||||
The metatheoretic properties of $\BCalc$ transfer to $\HCalc$ with
|
The metatheoretic properties of $\BCalc$ transfer to $\HCalc$ with
|
||||||
little extra effort, although we must amend the definition of
|
little extra effort, although we must amend the definition of
|
||||||
@@ -4706,37 +4733,77 @@ getting stuck on an unhandled operation.
|
|||||||
$\typ{\Gamma}{M' : C}$.
|
$\typ{\Gamma}{M' : C}$.
|
||||||
\end{theorem}
|
\end{theorem}
|
||||||
|
|
||||||
\section{\OSname{} in 50 lines of code or less}
|
\section{Composing \UNIX{} with effect handlers}
|
||||||
\label{sec:deep-handlers-in-action}
|
\label{sec:deep-handlers-in-action}
|
||||||
|
|
||||||
A systems software engineering reading of effect handlers may be to
|
There are several analogies for effect handlers, e.g. as interpreters
|
||||||
understand them as modular ``tiny operating systems''. Operationally,
|
for effects, folds over computation trees, etc. A particularly
|
||||||
how an \emph{operating system} interprets a set of \emph{system
|
compelling programmatic analogy for effect handlers is \emph{effect
|
||||||
commands} performed via \emph{system calls} is similar to how an
|
handlers as composable operating systems}. Effect handlers and
|
||||||
effect handler interprets a set of abstract operations performed via
|
operating systems share operational characteristics: an operating
|
||||||
operation invocations.
|
system interprets a set of system commands performed via system calls,
|
||||||
|
which is similar to how an effect handler interprets a set of abstract
|
||||||
|
operations performed via operation invocations. This analogy was
|
||||||
|
suggested to me by James McKinna (personal communication, 2017).
|
||||||
%
|
%
|
||||||
This reading was suggested to me by James McKinna (personal
|
The compelling aspect of this analogy is that we can understand a
|
||||||
communication). In this section I will take this reading literally,
|
monolithic and complex operating system like \UNIX{}~\cite{RitchieT74}
|
||||||
and demonstrate how we can use the power of (deep) effect handlers to
|
as a collection of effect handlers, or alternatively, a collection of
|
||||||
implement a tiny operating system that supports multiple users,
|
tiny operating systems, that when composed yield a semantics for
|
||||||
time-sharing, and file i/o.
|
\UNIX{}.
|
||||||
|
|
||||||
|
In this section we will take this reading of effect handlers
|
||||||
|
literally, and demonstrate how we can harness the power of (deep)
|
||||||
|
effect handlers to implement a \UNIX{}-style operating system with
|
||||||
|
multiple user sessions, time-sharing, and file i/o. We dub the system
|
||||||
|
\OSname{}.
|
||||||
%
|
%
|
||||||
The operating system will be a variation of \UNIX{}~\cite{RitchieT74},
|
It is a case study that demonstrates the versatility of effect
|
||||||
which we will call \OSname{}.
|
handlers, and shows how standard computational effects such as
|
||||||
%
|
\emph{exceptions}, \emph{dynamic binding}, \emph{nondeterminism}, and
|
||||||
To make the task tractable we will occasionally jump some hops and
|
\emph{state} make up the essence of an operating system.
|
||||||
make some simplifying assumptions, nevertheless the resulting
|
|
||||||
implementation will capture the essence of a \UNIX{}-like operating
|
For the sake of clarity, we will occasionally make some blatant
|
||||||
system.
|
simplifications, nevertheless the resulting implementation will
|
||||||
|
capture the essence of a \UNIX{}-like operating system.
|
||||||
%
|
%
|
||||||
The implementation will be composed of several small modular effect
|
The implementation will be composed of several small modular effect
|
||||||
handlers, that each handles a particular set of system commands. In
|
handlers, that each handles a particular set of system commands. In
|
||||||
this respect, we will truly realise \OSname{} in the spirit of the
|
this respect, we will truly realise \OSname{} in the spirit of the
|
||||||
\UNIX{} philosophy~\cite[Section~1.6]{Raymond03}. The implementation of
|
\UNIX{} philosophy~\cite[Section~1.6]{Raymond03}.
|
||||||
the operating system will showcase several computational effects in
|
|
||||||
action including \emph{dynamic binding}, \emph{nondeterminism}, and
|
% This case study demonstrates that we can decompose a monolithic
|
||||||
\emph{state}.
|
% operating system like \UNIX{} into a collection of specialised effect
|
||||||
|
% handlers. Each handler interprets a particular system command.
|
||||||
|
|
||||||
|
% A systems software engineering reading of effect handlers may be to
|
||||||
|
% understand them as modular ``tiny operating systems''. Operationally,
|
||||||
|
% how an \emph{operating system} interprets a set of \emph{system
|
||||||
|
% commands} performed via \emph{system calls} is similar to how an
|
||||||
|
% effect handler interprets a set of abstract operations performed via
|
||||||
|
% operation invocations.
|
||||||
|
% %
|
||||||
|
% This reading was suggested to me by James McKinna (personal
|
||||||
|
% communication). In this section I will take this reading literally,
|
||||||
|
% and demonstrate how we can use the power of (deep) effect handlers to
|
||||||
|
% implement a tiny operating system that supports multiple users,
|
||||||
|
% time-sharing, and file i/o.
|
||||||
|
% %
|
||||||
|
% The operating system will be a variation of \UNIX{}~\cite{RitchieT74},
|
||||||
|
% which we will call \OSname{}.
|
||||||
|
% %
|
||||||
|
% To make the task tractable we will occasionally jump some hops and
|
||||||
|
% make some simplifying assumptions, nevertheless the resulting
|
||||||
|
% implementation will capture the essence of a \UNIX{}-like operating
|
||||||
|
% system.
|
||||||
|
% %
|
||||||
|
% The implementation will be composed of several small modular effect
|
||||||
|
% handlers, that each handles a particular set of system commands. In
|
||||||
|
% this respect, we will truly realise \OSname{} in the spirit of the
|
||||||
|
% \UNIX{} philosophy~\cite[Section~1.6]{Raymond03}. The implementation of
|
||||||
|
% the operating system will showcase several computational effects in
|
||||||
|
% action including \emph{dynamic binding}, \emph{nondeterminism}, and
|
||||||
|
% \emph{state}.
|
||||||
|
|
||||||
\subsection{Basic i/o}
|
\subsection{Basic i/o}
|
||||||
\label{sec:tiny-unix-bio}
|
\label{sec:tiny-unix-bio}
|
||||||
|
|||||||
Reference in New Issue
Block a user