1
0
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:
2021-01-14 16:13:00 +00:00
parent 7e71992709
commit 46e36b5318
3 changed files with 170 additions and 66 deletions

View File

@@ -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}}

View File

@@ -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},

View File

@@ -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}