|
|
@ -14846,24 +14846,25 @@ the captured context and continuation invocation context to coincide. |
|
|
\def\LLL{{\mathcal L}} |
|
|
\def\LLL{{\mathcal L}} |
|
|
\def\N{{\mathbb N}} |
|
|
\def\N{{\mathbb N}} |
|
|
% |
|
|
% |
|
|
In today's programming languages we find a wealth of powerful |
|
|
|
|
|
constructs and features --- exceptions, higher-order store, dynamic |
|
|
|
|
|
method dispatch, coroutines, explicit continuations, concurrency |
|
|
|
|
|
features, Lisp-style `quote' and so on --- which may be present or |
|
|
|
|
|
absent in various combinations in any given language. There are of |
|
|
|
|
|
course many important pragmatic and stylistic differences between |
|
|
|
|
|
languages, but here we are concerned with whether languages may differ |
|
|
|
|
|
more essentially in their expressive power, according to the selection |
|
|
|
|
|
of features they contain. |
|
|
|
|
|
|
|
|
|
|
|
One can interpret this question in various ways. For instance, |
|
|
|
|
|
\citet{Felleisen91} considers the question of whether a language |
|
|
|
|
|
$\LLL$ admits a translation into a sublanguage $\LLL'$ in a way which |
|
|
|
|
|
respects not only the behaviour of programs but also aspects of their |
|
|
|
|
|
(global or local) syntactic structure. If the translation of some |
|
|
|
|
|
$\LLL$-program into $\LLL'$ requires a complete global restructuring, |
|
|
|
|
|
we may say that $\LLL'$ is in some way less expressive than $\LLL$. |
|
|
|
|
|
In the present paper, however, we have in mind even more fundamental |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
% In today's programming languages we find a wealth of powerful |
|
|
|
|
|
% constructs and features --- exceptions, higher-order store, dynamic |
|
|
|
|
|
% method dispatch, coroutines, explicit continuations, concurrency |
|
|
|
|
|
% features, Lisp-style `quote' and so on --- which may be present or |
|
|
|
|
|
% absent in various combinations in any given language. There are of |
|
|
|
|
|
% course many important pragmatic and stylistic differences between |
|
|
|
|
|
% languages, but here we are concerned with whether languages may differ |
|
|
|
|
|
% more essentially in their expressive power, according to the selection |
|
|
|
|
|
% of features they contain. |
|
|
|
|
|
|
|
|
|
|
|
% One can interpret this question in various ways. For instance, |
|
|
|
|
|
% \citet{Felleisen91} considers the question of whether a language |
|
|
|
|
|
% $\LLL$ admits a translation into a sublanguage $\LLL'$ in a way which |
|
|
|
|
|
% respects not only the behaviour of programs but also aspects of their |
|
|
|
|
|
% (global or local) syntactic structure. If the translation of some |
|
|
|
|
|
% $\LLL$-program into $\LLL'$ requires a complete global restructuring, |
|
|
|
|
|
% we may say that $\LLL'$ is in some way less expressive than $\LLL$. |
|
|
|
|
|
However, in this chapter we will look at even more fundamental |
|
|
expressivity differences that would not be bridged even if |
|
|
expressivity differences that would not be bridged even if |
|
|
whole-program translations were admitted. These fall under two |
|
|
whole-program translations were admitted. These fall under two |
|
|
headings. |
|
|
headings. |
|
|
@ -14876,9 +14877,9 @@ headings. |
|
|
achieved in $\LLL'$? |
|
|
achieved in $\LLL'$? |
|
|
\end{enumerate} |
|
|
\end{enumerate} |
|
|
% |
|
|
% |
|
|
We may also ask: are there examples of \emph{natural, practically |
|
|
|
|
|
useful} operations that manifest such differences? If so, this |
|
|
|
|
|
might be considered as a significant advantage of $\LLL$ over $\LLL'$. |
|
|
|
|
|
|
|
|
% We may also ask: are there examples of \emph{natural, practically |
|
|
|
|
|
% useful} operations that manifest such differences? If so, this |
|
|
|
|
|
% might be considered as a significant advantage of $\LLL$ over $\LLL'$. |
|
|
|
|
|
|
|
|
If the `operations' we are asking about are ordinary first-order |
|
|
If the `operations' we are asking about are ordinary first-order |
|
|
functions --- that is, both their inputs and outputs are of ground |
|
|
functions --- that is, both their inputs and outputs are of ground |
|
|
@ -14917,8 +14918,8 @@ but not in a typical `sequential' programming |
|
|
language~\cite{Plotkin77}. It is also well known that the presence of |
|
|
language~\cite{Plotkin77}. It is also well known that the presence of |
|
|
control features or local state enables observational distinctions |
|
|
control features or local state enables observational distinctions |
|
|
that cannot be made in a purely functional setting: for instance, |
|
|
that cannot be made in a purely functional setting: for instance, |
|
|
there are programs involving `call/cc' that detect the order in which |
|
|
|
|
|
a (call-by-name) `+' operation evaluates its arguments |
|
|
|
|
|
|
|
|
there are programs involving call/cc that detect the order in which a |
|
|
|
|
|
(call-by-name) `+' operation evaluates its arguments |
|
|
\citep{CartwrightF92}. Such operations are `non-functional' in the |
|
|
\citep{CartwrightF92}. Such operations are `non-functional' in the |
|
|
sense that their output is not determined solely by the extension of |
|
|
sense that their output is not determined solely by the extension of |
|
|
their input (seen as a mathematical function |
|
|
their input (seen as a mathematical function |
|
|
@ -14936,28 +14937,28 @@ low-order recursion but not by high-order iteration |
|
|
theory of some of the natural notions of higher-order computability |
|
|
theory of some of the natural notions of higher-order computability |
|
|
that arise in this way, is mapped out by \citet{LongleyN15}. |
|
|
that arise in this way, is mapped out by \citet{LongleyN15}. |
|
|
|
|
|
|
|
|
Relatively few results of this character have so far been established |
|
|
|
|
|
on the complexity side. \citet{Pippenger96} gives an example of an |
|
|
|
|
|
`online' operation on infinite sequences of atomic symbols |
|
|
|
|
|
(essentially a function from streams to streams) such that the first |
|
|
|
|
|
$n$ output symbols can be produced within time $\BigO(n)$ if one is |
|
|
|
|
|
working in an `impure' version of Lisp (in which mutation of `cons' |
|
|
|
|
|
pairs is admitted), but with a worst-case runtime no better than |
|
|
|
|
|
$\Omega(n \log n)$ for any implementation in pure Lisp (without such |
|
|
|
|
|
mutation). This example was reconsidered by \citet{BirdJdM97} who |
|
|
|
|
|
showed that the same speedup can be achieved in a pure language by |
|
|
|
|
|
using lazy evaluation. Another candidate is the familiar $\log n$ |
|
|
|
|
|
overhead involved in implementing maps (supporting lookup and |
|
|
|
|
|
extension) in a pure functional language \cite{Okasaki99}, although to |
|
|
|
|
|
our knowledge this situation has not yet been subjected to theoretical |
|
|
|
|
|
scrutiny. \citet{Jones01} explores the approach of manifesting |
|
|
|
|
|
expressivity and efficiency differences between certain languages by |
|
|
|
|
|
artificially restricting attention to `cons-free' programs; in this |
|
|
|
|
|
setting, the classes of representable first-order functions for the |
|
|
|
|
|
various languages are found to coincide with some well-known |
|
|
|
|
|
complexity classes. |
|
|
|
|
|
|
|
|
|
|
|
The purpose of the present paper is to give a clear example of such an |
|
|
|
|
|
|
|
|
% Relatively few results of this character have so far been established |
|
|
|
|
|
% on the complexity side. \citet{Pippenger96} gives an example of an |
|
|
|
|
|
% `online' operation on infinite sequences of atomic symbols |
|
|
|
|
|
% (essentially a function from streams to streams) such that the first |
|
|
|
|
|
% $n$ output symbols can be produced within time $\BigO(n)$ if one is |
|
|
|
|
|
% working in an `impure' version of Lisp (in which mutation of `cons' |
|
|
|
|
|
% pairs is admitted), but with a worst-case runtime no better than |
|
|
|
|
|
% $\Omega(n \log n)$ for any implementation in pure Lisp (without such |
|
|
|
|
|
% mutation). This example was reconsidered by \citet{BirdJdM97} who |
|
|
|
|
|
% showed that the same speedup can be achieved in a pure language by |
|
|
|
|
|
% using lazy evaluation. Another candidate is the familiar $\log n$ |
|
|
|
|
|
% overhead involved in implementing maps (supporting lookup and |
|
|
|
|
|
% extension) in a pure functional language \cite{Okasaki99}, although to |
|
|
|
|
|
% our knowledge this situation has not yet been subjected to theoretical |
|
|
|
|
|
% scrutiny. \citet{Jones01} explores the approach of manifesting |
|
|
|
|
|
% expressivity and efficiency differences between certain languages by |
|
|
|
|
|
% artificially restricting attention to `cons-free' programs; in this |
|
|
|
|
|
% setting, the classes of representable first-order functions for the |
|
|
|
|
|
% various languages are found to coincide with some well-known |
|
|
|
|
|
% complexity classes. |
|
|
|
|
|
|
|
|
|
|
|
The purpose of this chapter is to give a clear example of such an |
|
|
inherent complexity difference higher up in the expressivity spectrum. |
|
|
inherent complexity difference higher up in the expressivity spectrum. |
|
|
Specifically, we consider the following \emph{generic count} problem, |
|
|
Specifically, we consider the following \emph{generic count} problem, |
|
|
parametric in $n$: given a boolean-valued predicate $P$ on the space |
|
|
parametric in $n$: given a boolean-valued predicate $P$ on the space |
|
|
@ -14981,9 +14982,8 @@ $\Omega(n 2^n)$ runtime. Moreover, we shall show that in a typical |
|
|
call-by-value language without advanced control features, one cannot |
|
|
call-by-value language without advanced control features, one cannot |
|
|
improve on this: \emph{any} implementation of $\Count_n$ must |
|
|
improve on this: \emph{any} implementation of $\Count_n$ must |
|
|
necessarily take time $\Omega(n2^n)$ on \emph{any} predicate $P$. On |
|
|
necessarily take time $\Omega(n2^n)$ on \emph{any} predicate $P$. On |
|
|
the other hand, if we extend our language with a feature such as |
|
|
|
|
|
\emph{effect handlers} (see Section~\ref{sec:handlers-primer} below), |
|
|
|
|
|
it becomes possible to bring the runtime down to $\BigO(2^n)$: an |
|
|
|
|
|
|
|
|
the other hand, if we extend our language with effect handlers, it |
|
|
|
|
|
becomes possible to bring the runtime down to $\BigO(2^n)$: an |
|
|
asymptotic gain of a factor of $n$. |
|
|
asymptotic gain of a factor of $n$. |
|
|
|
|
|
|
|
|
The \emph{generic search} problem is just like the generic count |
|
|
The \emph{generic search} problem is just like the generic count |
|
|
@ -15031,78 +15031,102 @@ precisely to show that our languages differ in an essential way |
|
|
\emph{as regards their power to manipulate data of type} $(\Nat \to |
|
|
\emph{as regards their power to manipulate data of type} $(\Nat \to |
|
|
\Bool) \to \Bool$. |
|
|
\Bool) \to \Bool$. |
|
|
|
|
|
|
|
|
This idea of using first-class control to achieve `backtracking' has |
|
|
|
|
|
|
|
|
This idea of using first-class control to achieve backtracking has |
|
|
been exploited before and is fairly widely known (see |
|
|
been exploited before and is fairly widely known (see |
|
|
e.g. \citep{KiselyovSFA05}), and there is a clear programming |
|
|
e.g. \citep{KiselyovSFA05}), and there is a clear programming |
|
|
intuition that this yields a speedup unattainable in languages without |
|
|
intuition that this yields a speedup unattainable in languages without |
|
|
such control features. Our main contribution in this paper is to |
|
|
|
|
|
provide, for the first time, a precise mathematical theorem that pins |
|
|
|
|
|
down this fundamental efficiency difference, thus giving formal |
|
|
|
|
|
substance to this intuition. Since our goal is to give a realistic |
|
|
|
|
|
analysis of the efficiency achievable in various settings without |
|
|
|
|
|
getting bogged down in inessential implementation details, we shall |
|
|
|
|
|
work concretely and operationally with the languages in question, |
|
|
|
|
|
using a CEK-style abstract machine semantics as our basic model of |
|
|
|
|
|
execution time, and with some specific programs in these languages. |
|
|
|
|
|
In the first instance, we formulate our results as a comparison |
|
|
|
|
|
between a purely functional base language (a version of call-by-value |
|
|
|
|
|
PCF) and an extension with first-class control; we then indicate how |
|
|
|
|
|
these results can be extended to base languages with other features |
|
|
|
|
|
such as mutable state. |
|
|
|
|
|
|
|
|
|
|
|
In summary, our purpose is to exhibit an efficiency gap which, in our |
|
|
|
|
|
view, manifests a fundamental feature of the programming language |
|
|
|
|
|
landscape, challenging a common assumption that all real-world |
|
|
|
|
|
programming languages are essentially `equivalent' from an asymptotic |
|
|
|
|
|
point of view. We believe that such results are important not only |
|
|
|
|
|
for a rounded understanding of the relative merits of existing |
|
|
|
|
|
languages, but also for informing future language design. |
|
|
|
|
|
|
|
|
|
|
|
For their convenience as structured delimited control operators we |
|
|
|
|
|
adopt effect handlers as our universal control abstraction of choice, |
|
|
|
|
|
but our results adapt mutatis mutandis to other first-class control |
|
|
|
|
|
abstractions such as `call/cc'~\cite{AbelsonHAKBOBPCRFRHSHW85}, `control' |
|
|
|
|
|
($\mathcal{F}$) and 'prompt' ($\textbf{\#}$)~\citep{Felleisen88}, or |
|
|
|
|
|
`shift' and `reset'~\citep{DanvyF90}. |
|
|
|
|
|
|
|
|
|
|
|
The rest of the paper is structured as follows. |
|
|
|
|
|
\begin{itemize} |
|
|
|
|
|
\item Section~\ref{sec:handlers-primer} provides an introduction to |
|
|
|
|
|
effect handlers as a programming abstraction. |
|
|
|
|
|
\item Section~\ref{sec:calculi} presents a PCF-like language |
|
|
|
|
|
$\BPCF$ and its extension $\HPCF$ with effect handlers. |
|
|
|
|
|
\item Section~\ref{sec:abstract-machine-semantics} defines abstract |
|
|
|
|
|
machines for $\BPCF$ and $\HPCF$, yielding a runtime cost model. |
|
|
|
|
|
\item Section~\ref{sec:generic-search} introduces generic count and |
|
|
|
|
|
some associated machinery, and presents an implementation in |
|
|
|
|
|
$\HPCF$ with runtime $\BigO(2^n)$. |
|
|
|
|
|
\item Section~\ref{sec:pure-counting} establishes that any generic |
|
|
|
|
|
count implementation in $\BCalc$ must have runtime $\Omega(n2^n)$. |
|
|
|
|
|
\item Section~\ref{sec:robustness} shows that our results scale to |
|
|
|
|
|
richer settings including support for a wider class of predicates, |
|
|
|
|
|
the adaptation from generic count to generic search, and an |
|
|
|
|
|
extension of the base language with state. |
|
|
|
|
|
\item Section~\ref{sec:experiments} evaluates implementations of |
|
|
|
|
|
generic search based on $\BPCF$ and $\HPCF$ in Standard ML. |
|
|
|
|
|
\item Section \ref{sec:conclusions} concludes. |
|
|
|
|
|
\end{itemize} |
|
|
|
|
|
% |
|
|
|
|
|
The languages $\BPCF$ and $\HPCF$ are rather minimal versions of |
|
|
|
|
|
previously studied systems --- we only include the machinery needed |
|
|
|
|
|
for illustrating the generic search efficiency phenomenon. |
|
|
|
|
|
% |
|
|
|
|
|
Auxiliary results are included in the appendices of the extended |
|
|
|
|
|
version of the paper~\citep{HillerstromLL20}. |
|
|
|
|
|
|
|
|
such control features. % Our main contribution in this paper is to |
|
|
|
|
|
% provide, for the first time, a precise mathematical theorem that pins |
|
|
|
|
|
% down this fundamental efficiency difference, thus giving formal |
|
|
|
|
|
% substance to this intuition. Since our goal is to give a realistic |
|
|
|
|
|
% analysis of the efficiency achievable in various settings without |
|
|
|
|
|
% getting bogged down in inessential implementation details, we shall |
|
|
|
|
|
% work concretely and operationally with the languages in question, |
|
|
|
|
|
% using a CEK-style abstract machine semantics as our basic model of |
|
|
|
|
|
% execution time, and with some specific programs in these languages. |
|
|
|
|
|
% In the first instance, we formulate our results as a comparison |
|
|
|
|
|
% between a purely functional base language (a version of call-by-value |
|
|
|
|
|
% PCF) and an extension with first-class control; we then indicate how |
|
|
|
|
|
% these results can be extended to base languages with other features |
|
|
|
|
|
% such as mutable state. |
|
|
|
|
|
|
|
|
|
|
|
\paragraph{Relation to prior work} This chapter is based entirely on |
|
|
|
|
|
the following previously published paper. |
|
|
|
|
|
\begin{enumerate} |
|
|
|
|
|
\item[~] \bibentry{HillerstromLL20} |
|
|
|
|
|
\end{enumerate} |
|
|
|
|
|
The contents of Sections~\ref{sec:calculi}, |
|
|
|
|
|
\ref{sec:abstract-machine-semantics}, \ref{sec:generic-search}, |
|
|
|
|
|
\ref{sec:pure-counting}, \ref{sec:robustness}, and |
|
|
|
|
|
\ref{sec:experiments} are almost verbatim copies of Sections 3, 4, 5, |
|
|
|
|
|
6, 7, and 8 of the above paper. I have made a few stylistic |
|
|
|
|
|
adjustments to make the Sections fit with the rest of this |
|
|
|
|
|
dissertation. |
|
|
|
|
|
|
|
|
|
|
|
% In summary, our purpose is to exhibit an efficiency gap which, in our |
|
|
|
|
|
% view, manifests a fundamental feature of the programming language |
|
|
|
|
|
% landscape, challenging a common assumption that all real-world |
|
|
|
|
|
% programming languages are essentially `equivalent' from an asymptotic |
|
|
|
|
|
% point of view. We believe that such results are important not only |
|
|
|
|
|
% for a rounded understanding of the relative merits of existing |
|
|
|
|
|
% languages, but also for informing future language design. |
|
|
|
|
|
|
|
|
|
|
|
% For their convenience as structured delimited control operators we |
|
|
|
|
|
% adopt effect handlers as our universal control abstraction of choice, |
|
|
|
|
|
% but our results adapt mutatis mutandis to other first-class control |
|
|
|
|
|
% abstractions such as `call/cc'~\cite{AbelsonHAKBOBPCRFRHSHW85}, `control' |
|
|
|
|
|
% ($\mathcal{F}$) and 'prompt' ($\textbf{\#}$)~\citep{Felleisen88}, or |
|
|
|
|
|
% `shift' and `reset'~\citep{DanvyF90}. |
|
|
|
|
|
|
|
|
|
|
|
% The rest of the paper is structured as follows. |
|
|
|
|
|
% \begin{itemize} |
|
|
|
|
|
% \item Section~\ref{sec:handlers-primer} provides an introduction to |
|
|
|
|
|
% effect handlers as a programming abstraction. |
|
|
|
|
|
% \item Section~\ref{sec:calculi} presents a PCF-like language |
|
|
|
|
|
% $\BPCF$ and its extension $\HPCF$ with effect handlers. |
|
|
|
|
|
% \item Section~\ref{sec:abstract-machine-semantics} defines abstract |
|
|
|
|
|
% machines for $\BPCF$ and $\HPCF$, yielding a runtime cost model. |
|
|
|
|
|
% \item Section~\ref{sec:generic-search} introduces generic count and |
|
|
|
|
|
% some associated machinery, and presents an implementation in |
|
|
|
|
|
% $\HPCF$ with runtime $\BigO(2^n)$. |
|
|
|
|
|
% \item Section~\ref{sec:pure-counting} establishes that any generic |
|
|
|
|
|
% count implementation in $\BCalc$ must have runtime $\Omega(n2^n)$. |
|
|
|
|
|
% \item Section~\ref{sec:robustness} shows that our results scale to |
|
|
|
|
|
% richer settings including support for a wider class of predicates, |
|
|
|
|
|
% the adaptation from generic count to generic search, and an |
|
|
|
|
|
% extension of the base language with state. |
|
|
|
|
|
% \item Section~\ref{sec:experiments} evaluates implementations of |
|
|
|
|
|
% generic search based on $\BPCF$ and $\HPCF$ in Standard ML. |
|
|
|
|
|
% \item Section \ref{sec:conclusions} concludes. |
|
|
|
|
|
% \end{itemize} |
|
|
|
|
|
% % |
|
|
|
|
|
% The languages $\BPCF$ and $\HPCF$ are rather minimal versions of |
|
|
|
|
|
% previously studied systems --- we only include the machinery needed |
|
|
|
|
|
% for illustrating the generic search efficiency phenomenon. |
|
|
|
|
|
% % |
|
|
|
|
|
% Auxiliary results are included in the appendices of the extended |
|
|
|
|
|
% version of the paper~\citep{HillerstromLL20}. |
|
|
|
|
|
|
|
|
%% |
|
|
%% |
|
|
%% Base calculus |
|
|
%% Base calculus |
|
|
%% |
|
|
%% |
|
|
\section{Calculi} |
|
|
\section{Calculi} |
|
|
\label{sec:calculi} |
|
|
\label{sec:calculi} |
|
|
In this section, we present our base language $\BPCF$ and its |
|
|
|
|
|
extension with effect handlers $\HPCF$. |
|
|
|
|
|
|
|
|
In this section, we present a base language $\BPCF$ and its extension |
|
|
|
|
|
with effect handlers $\HPCF$, both of which amounts to simply-typed |
|
|
|
|
|
variations of $\BCalc$ and $\HCalc$, |
|
|
|
|
|
respectively. Sections~\ref{sec:base-calculus}--\ref{sec:handler-machine} |
|
|
|
|
|
essentially recast the developments of |
|
|
|
|
|
Chapters~\ref{ch:base-language}, \ref{ch:unary-handlers}, and |
|
|
|
|
|
\ref{ch:abstract-machine} to fit the calculi $\BPCF$ and $\HPCF$. I |
|
|
|
|
|
reproduce the details here, even though, they are mostly the same as |
|
|
|
|
|
in the previous chapters save for a few tricks such as a crucial |
|
|
|
|
|
design decision in Section~\ref{sec:handlers-calculus} which makes it |
|
|
|
|
|
possible to implement continuation reification as a constant time |
|
|
|
|
|
operation. |
|
|
|
|
|
|
|
|
\subsection{Base Calculus} |
|
|
|
|
|
|
|
|
\subsection{Base calculus} |
|
|
|
|
|
\label{sec:base-calculus} |
|
|
The base calculus $\BPCF$ is a fine-grain |
|
|
The base calculus $\BPCF$ is a fine-grain |
|
|
call-by-value~\cite{LevyPT03} variation of PCF~\cite{Plotkin77}. |
|
|
call-by-value~\cite{LevyPT03} variation of PCF~\cite{Plotkin77}. |
|
|
% |
|
|
% |
|
|
@ -15114,7 +15138,7 @@ The syntax of $\BCalc$ is as follows. |
|
|
{\noindent |
|
|
{\noindent |
|
|
\begin{syntax} |
|
|
\begin{syntax} |
|
|
\slab{Types} &A,B,C,D\in\TypeCat &::= & \Nat \mid \One \mid A \to B \mid A \times B \mid A + B \\ |
|
|
\slab{Types} &A,B,C,D\in\TypeCat &::= & \Nat \mid \One \mid A \to B \mid A \times B \mid A + B \\ |
|
|
\slab{Type\textrm{ }Environments} &\Gamma\in\CtxCat &::= & \cdot \mid \Gamma, x:A \\ |
|
|
|
|
|
|
|
|
\slab{Type\textrm{ }environments} &\Gamma\in\TyEnvCat &::= & \cdot \mid \Gamma, x:A \\ |
|
|
\slab{Values} &V,W\in\ValCat &::= & x \mid k \mid c \mid \lambda x^A .\, M \mid \Rec \; f^{A \to B}\, x.M \\ |
|
|
\slab{Values} &V,W\in\ValCat &::= & x \mid k \mid c \mid \lambda x^A .\, M \mid \Rec \; f^{A \to B}\, x.M \\ |
|
|
& &\mid& \Unit \mid \Record{V, W} \mid (\Inl\, V)^B \mid (\Inr\, W)^A\\ |
|
|
& &\mid& \Unit \mid \Record{V, W} \mid (\Inl\, V)^B \mid (\Inr\, W)^A\\ |
|
|
% & & & |
|
|
% & & & |
|
|
@ -15281,7 +15305,7 @@ The constants have the following types. |
|
|
\begin{figure*} |
|
|
\begin{figure*} |
|
|
\begin{reductions} |
|
|
\begin{reductions} |
|
|
\semlab{App} & (\lambda x^A . \, M) V &\reducesto& M[V/x] \\ |
|
|
\semlab{App} & (\lambda x^A . \, M) V &\reducesto& M[V/x] \\ |
|
|
\semlab{App\textrm{-}Rec} & (\Rec\; f^A \,x.\, M) V &\reducesto& M[(\Rec\;f^A\,x .\,M)/f,V/x]\\ |
|
|
|
|
|
|
|
|
\semlab{AppRec} & (\Rec\; f^A \,x.\, M) V &\reducesto& M[(\Rec\;f^A\,x .\,M)/f,V/x]\\ |
|
|
\semlab{Const} & c~V &\reducesto& \Return\;(\const{c}\,(V)) \\ |
|
|
\semlab{Const} & c~V &\reducesto& \Return\;(\const{c}\,(V)) \\ |
|
|
\semlab{Split} & \Let \; \Record{x,y} = \Record{V,W} \; \In \; N &\reducesto& N[V/x,W/y] \\ |
|
|
\semlab{Split} & \Let \; \Record{x,y} = \Record{V,W} \; \In \; N &\reducesto& N[V/x,W/y] \\ |
|
|
\semlab{Case\textrm{-}inl} & |
|
|
\semlab{Case\textrm{-}inl} & |
|
|
@ -15310,8 +15334,8 @@ on closed values. The reduction relation $\reducesto$ is defined on |
|
|
computation terms. The statement $M \reducesto N$ reads: term $M$ |
|
|
computation terms. The statement $M \reducesto N$ reads: term $M$ |
|
|
reduces to term $N$ in one step. |
|
|
reduces to term $N$ in one step. |
|
|
% |
|
|
% |
|
|
We write $R^+$ for the transitive closure of relation $R$ and $R^*$ |
|
|
|
|
|
for the reflexive, transitive closure of relation $R$. |
|
|
|
|
|
|
|
|
% We write $R^+$ for the transitive closure of relation $R$ and $R^*$ |
|
|
|
|
|
% for the reflexive, transitive closure of relation $R$. |
|
|
|
|
|
|
|
|
\paragraph{Notation} |
|
|
\paragraph{Notation} |
|
|
% |
|
|
% |
|
|
@ -15372,7 +15396,7 @@ We use the standard encoding of booleans as a sum: |
|
|
% |
|
|
% |
|
|
% Handlers extension |
|
|
% Handlers extension |
|
|
% |
|
|
% |
|
|
\subsection{Handler Calculus} |
|
|
|
|
|
|
|
|
\subsection{Handler calculus} |
|
|
\label{sec:handlers-calculus} |
|
|
\label{sec:handlers-calculus} |
|
|
|
|
|
|
|
|
We now define $\HCalc$ as an extension of $\BCalc$. |
|
|
We now define $\HCalc$ as an extension of $\BCalc$. |
|
|
@ -15420,6 +15444,17 @@ forwarding: |
|
|
\[ |
|
|
\[ |
|
|
\{\OpCase{\ell}{p}{r} \mapsto \Let\; x \revto \Do \; \ell \, p \;\In\; r \, x\}. |
|
|
\{\OpCase{\ell}{p}{r} \mapsto \Let\; x \revto \Do \; \ell \, p \;\In\; r \, x\}. |
|
|
\] |
|
|
\] |
|
|
|
|
|
% |
|
|
|
|
|
\paragraph{Remark} |
|
|
|
|
|
This convention makes effect forwarding explicit, whereas in |
|
|
|
|
|
$\HCalc$ effect forwarding was implicit. As we shall see soon, an |
|
|
|
|
|
important semantic consequence of making effect forwarding explicit |
|
|
|
|
|
is that the abstract machine model in |
|
|
|
|
|
Section~\ref{sec:handler-machine} has no rule for effect forwarding |
|
|
|
|
|
as it instead happens as a sequence of explicit $\Do$ invocations in |
|
|
|
|
|
the term language. As a result, we become able to reason about |
|
|
|
|
|
continuation reification as a constant time operation, because a |
|
|
|
|
|
$\Do$ invocation will just reify the top-most continuation frame.\medskip |
|
|
|
|
|
|
|
|
\begin{figure*} |
|
|
\begin{figure*} |
|
|
\raggedright |
|
|
\raggedright |
|
|
@ -15437,15 +15472,15 @@ forwarding: |
|
|
\textbf{Handlers} |
|
|
\textbf{Handlers} |
|
|
\begin{mathpar} |
|
|
\begin{mathpar} |
|
|
\inferrule*[Lab=\tylab{Handler}] |
|
|
\inferrule*[Lab=\tylab{Handler}] |
|
|
{ \hret = \{\Val \; x \mapsto M\} \\ |
|
|
|
|
|
[\hell = \{\ell \, p \; r \mapsto N_\ell\}]_{\ell \in dom(\Sigma)} \\\\ |
|
|
|
|
|
|
|
|
{ \hret = \{\Return \; x \mapsto M\} \\ |
|
|
|
|
|
[\hell = \{\OpCase{\ell}{p}{r} \mapsto N_\ell\}]_{\ell \in dom(\Sigma)} \\\\ |
|
|
\typ{\Gamma, x : C}{M : D} \\ |
|
|
\typ{\Gamma, x : C}{M : D} \\ |
|
|
[\typ{\Gamma, p : A_\ell, r : B_\ell \to D}{N_\ell : D}]_{(\ell : A_\ell \to B_\ell) \in \Sigma} |
|
|
[\typ{\Gamma, p : A_\ell, r : B_\ell \to D}{N_\ell : D}]_{(\ell : A_\ell \to B_\ell) \in \Sigma} |
|
|
} |
|
|
} |
|
|
{{\Gamma} \vdash {H : C \Rightarrow D}} |
|
|
{{\Gamma} \vdash {H : C \Rightarrow D}} |
|
|
\end{mathpar} |
|
|
\end{mathpar} |
|
|
|
|
|
|
|
|
\caption{Additional typing rules for $\HPCF$} |
|
|
|
|
|
|
|
|
\caption{Additional typing rules for $\HPCF$.} |
|
|
\label{fig:typing-handlers} |
|
|
\label{fig:typing-handlers} |
|
|
\end{figure*} |
|
|
\end{figure*} |
|
|
|
|
|
|
|
|
@ -15489,7 +15524,7 @@ for handling operation invocations. |
|
|
\text{where } \hret = \{ \Return \; x \mapsto N \} \smallskip\\ |
|
|
\text{where } \hret = \{ \Return \; x \mapsto N \} \smallskip\\ |
|
|
\semlab{Op} & \Handle \; \EC[\Do \; \ell \, V] \; \With \; H &\reducesto& N[V/p,(\lambda y.\Handle \; \EC[\Return \; y] \; \With \; H)/r],\\ |
|
|
\semlab{Op} & \Handle \; \EC[\Do \; \ell \, V] \; \With \; H &\reducesto& N[V/p,(\lambda y.\Handle \; \EC[\Return \; y] \; \With \; H)/r],\\ |
|
|
\multicolumn{4}{@{}r@{}}{ |
|
|
\multicolumn{4}{@{}r@{}}{ |
|
|
\hfill\text{where } \hell = \{ \ell\, p \; r \mapsto N \} |
|
|
|
|
|
|
|
|
\hfill\text{where } \hell = \{ \OpCase{\ell}{p}{r} \mapsto N \} |
|
|
} |
|
|
} |
|
|
\end{reductions}}% |
|
|
\end{reductions}}% |
|
|
% |
|
|
% |
|
|
@ -15558,7 +15593,7 @@ Readers familiar with effect handlers may wonder why our handler |
|
|
calculus does not include an effect type system. |
|
|
calculus does not include an effect type system. |
|
|
% |
|
|
% |
|
|
As types frame the comparison of programs between languages, we |
|
|
As types frame the comparison of programs between languages, we |
|
|
require that types be fixed across languages; hence $\HCalc$ does not |
|
|
|
|
|
|
|
|
require that types be fixed across languages; hence $\HPCF$ does not |
|
|
include effect types. |
|
|
include effect types. |
|
|
% |
|
|
% |
|
|
Future work includes reconciling effect typing with our approach to |
|
|
Future work includes reconciling effect typing with our approach to |
|
|
@ -15573,8 +15608,10 @@ For each calculus we have given a \emph{small-step operational |
|
|
semantics} which uses a substitution model for evaluation. Whilst |
|
|
semantics} which uses a substitution model for evaluation. Whilst |
|
|
this model is semantically pleasing, it falls short of providing a |
|
|
this model is semantically pleasing, it falls short of providing a |
|
|
realistic account of practical computation as substitution is an |
|
|
realistic account of practical computation as substitution is an |
|
|
expensive operation. We now develop a more practical model of |
|
|
|
|
|
computation based on an \emph{abstract machine semantics}. |
|
|
|
|
|
|
|
|
expensive operation. Instead we shall use a slightly simpler variation |
|
|
|
|
|
of the abstract machine from Chapter~\ref{ch:abstract-machine} as it |
|
|
|
|
|
provides a more practical model of computation (it is simpler, because |
|
|
|
|
|
the source language is simpler). |
|
|
|
|
|
|
|
|
\subsection{Base machine} |
|
|
\subsection{Base machine} |
|
|
\label{sec:base-abstract-machine} |
|
|
\label{sec:base-abstract-machine} |
|
|
@ -15583,16 +15620,12 @@ computation based on an \emph{abstract machine semantics}. |
|
|
\newcommand{\EConf}{\dec{EConf}} |
|
|
\newcommand{\EConf}{\dec{EConf}} |
|
|
\newcommand{\MVal}{\dec{MVal}} |
|
|
\newcommand{\MVal}{\dec{MVal}} |
|
|
|
|
|
|
|
|
We choose a \emph{CEK}-style abstract machine |
|
|
|
|
|
semantics~\citep{FelleisenF86} for \BCalc{} based on that of |
|
|
|
|
|
\citet{HillerstromLA20}. |
|
|
|
|
|
% |
|
|
|
|
|
The CEK machine operates on configurations which are triples of the |
|
|
|
|
|
form $\cek{M \mid \gamma \mid \sigma}$. The first component contains |
|
|
|
|
|
the computation currently being evaluated. The second component |
|
|
|
|
|
contains the environment $\gamma$ which binds free variables. The |
|
|
|
|
|
third component contains the continuation which instructs the machine |
|
|
|
|
|
how to proceed once evaluation of the current computation is complete. |
|
|
|
|
|
|
|
|
The base machine operates on configurations of the form |
|
|
|
|
|
$\cek{M \mid \gamma \mid \sigma}$. The first component contains the |
|
|
|
|
|
computation currently being evaluated. The second component contains |
|
|
|
|
|
the environment $\gamma$ which binds free variables. The third |
|
|
|
|
|
component contains the continuation which instructs the machine how to |
|
|
|
|
|
proceed once evaluation of the current computation is complete. |
|
|
% |
|
|
% |
|
|
The syntax of abstract machine states is as follows. |
|
|
The syntax of abstract machine states is as follows. |
|
|
{ |
|
|
{ |
|
|
@ -15600,10 +15633,10 @@ The syntax of abstract machine states is as follows. |
|
|
\slab{Configurations} & \conf \in \Conf &::=& \cek{M \mid \env \mid \sigma} \\ |
|
|
\slab{Configurations} & \conf \in \Conf &::=& \cek{M \mid \env \mid \sigma} \\ |
|
|
% & &\mid& \cekop{M \mid \env \mid \kappa \mid \kappa'} \\ |
|
|
% & &\mid& \cekop{M \mid \env \mid \kappa \mid \kappa'} \\ |
|
|
\slab{Environments} &\env \in \Env &::=& \emptyset \mid \env[x \mapsto v] \\ |
|
|
\slab{Environments} &\env \in \Env &::=& \emptyset \mid \env[x \mapsto v] \\ |
|
|
\slab{Machine values} &v, w \in \MVal &::= & x \mid n \mid c \mid \Unit \mid \Record{v, w} \\ |
|
|
|
|
|
& &\mid& (\env, \lambda x^A .\, M) \mid (\env, \Rec\, f^{A \to B}\,x . \, M) |
|
|
|
|
|
\mid (\Inl\, v)^B \mid (\Inr\,w)^A \\ |
|
|
|
|
|
\slab{Pure continuations} &\sigma \in \PureCont &::=& \nil \mid (\env, x, N) \cons \sigma \\ |
|
|
|
|
|
|
|
|
\slab{Machine\textrm{ }values} &v, w \in \MValCat &::= & x \mid n \mid c \mid \Unit \mid \Record{v, w} \\ |
|
|
|
|
|
& &\mid& (\env, \lambda x^A .\, M) \mid (\env, \Rec\, f^{A \to B}\,x . \, M)\\ |
|
|
|
|
|
& &\mid& (\Inl\, v)^B \mid (\Inr\,w)^A \\ |
|
|
|
|
|
\slab{Pure\textrm{ }continuations} &\sigma \in \MPContCat &::=& \nil \mid (\env, x, N) \cons \sigma \\ |
|
|
\end{syntax}}% |
|
|
\end{syntax}}% |
|
|
% |
|
|
% |
|
|
Values consist of function closures, constants, pairs, and left or |
|
|
Values consist of function closures, constants, pairs, and left or |
|
|
@ -15622,15 +15655,17 @@ pattern matching to deconstruct pure continuations. |
|
|
|
|
|
|
|
|
\begin{figure*} |
|
|
\begin{figure*} |
|
|
\raggedright |
|
|
\raggedright |
|
|
\textbf{Transition relation} |
|
|
|
|
|
\begin{reductions} |
|
|
|
|
|
|
|
|
\textbf{Transition relation} $\qquad\qquad~~\,\stepsto\, \subseteq\! \MConfCat \times \MConfCat$ |
|
|
|
|
|
\[ |
|
|
|
|
|
\bl |
|
|
|
|
|
\ba{@{}l@{\quad}r@{~}c@{~}l@{~~}l@{}} |
|
|
% App |
|
|
% App |
|
|
\mlab{App} & \cek{ V\;W \mid \env \mid \sigma} |
|
|
\mlab{App} & \cek{ V\;W \mid \env \mid \sigma} |
|
|
&\stepsto& \cek{ M \mid \env'[x \mapsto \val{W}{\env}] \mid \sigma},\\ |
|
|
&\stepsto& \cek{ M \mid \env'[x \mapsto \val{W}{\env}] \mid \sigma},\\ |
|
|
&&& \quad\text{ if }\val{V}{\env} = (\env', \lambda x^A . \, M)\\ |
|
|
&&& \quad\text{ if }\val{V}{\env} = (\env', \lambda x^A . \, M)\\ |
|
|
|
|
|
|
|
|
% App rec |
|
|
% App rec |
|
|
\mlab{Rec} & \cek{ V\;W \mid \env \mid \sigma} |
|
|
|
|
|
|
|
|
\mlab{AppRec} & \cek{ V\;W \mid \env \mid \sigma} |
|
|
&\stepsto& \cek{ M \mid \env'[\bl |
|
|
&\stepsto& \cek{ M \mid \env'[\bl |
|
|
f \mapsto (\env', \Rec\,f^{A \to B}\,x. M), \\ |
|
|
f \mapsto (\env', \Rec\,f^{A \to B}\,x. M), \\ |
|
|
x \mapsto \val{W}{\env}] \mid \sigma},\\ |
|
|
x \mapsto \val{W}{\env}] \mid \sigma},\\ |
|
|
@ -15641,6 +15676,8 @@ pattern matching to deconstruct pure continuations. |
|
|
\mlab{Const} & \cek{ V~W \mid \env \mid \sigma} |
|
|
\mlab{Const} & \cek{ V~W \mid \env \mid \sigma} |
|
|
&\stepsto& \cek{ \Return\; (\const{c}\,(\val{W}\env)) \mid \env \mid \sigma},\\ |
|
|
&\stepsto& \cek{ \Return\; (\const{c}\,(\val{W}\env)) \mid \env \mid \sigma},\\ |
|
|
&&& \quad\text{ if }\val{V}{\env} = c \\ |
|
|
&&& \quad\text{ if }\val{V}{\env} = c \\ |
|
|
|
|
|
\ea \medskip\\ |
|
|
|
|
|
\ba{@{}l@{\quad}r@{~}c@{~}l@{~~}l@{}} |
|
|
\mlab{Split} & \cek{ \Let \; \Record{x,y} = V \; \In \; N \mid \env \mid \sigma} |
|
|
\mlab{Split} & \cek{ \Let \; \Record{x,y} = V \; \In \; N \mid \env \mid \sigma} |
|
|
&\stepsto& \cek{ N \mid \env[x \mapsto v, y \mapsto w] \mid \sigma}, \\ |
|
|
&\stepsto& \cek{ N \mid \env[x \mapsto v, y \mapsto w] \mid \sigma}, \\ |
|
|
&&& \quad\text{ if }\val{V}{\env} = \Record{v; w} \\ |
|
|
&&& \quad\text{ if }\val{V}{\env} = \Record{v; w} \\ |
|
|
@ -15650,52 +15687,54 @@ pattern matching to deconstruct pure continuations. |
|
|
\cekl \Case\; V\, \{&\Inl\, x \mapsto M; \\ |
|
|
\cekl \Case\; V\, \{&\Inl\, x \mapsto M; \\ |
|
|
&\Inr\, y \mapsto N\} \mid \env \mid \sigma \cekr \\ |
|
|
&\Inr\, y \mapsto N\} \mid \env \mid \sigma \cekr \\ |
|
|
\ea |
|
|
\ea |
|
|
&\stepsto& \cek{ M \mid \env[x \mapsto v] \mid \sigma},\\ |
|
|
|
|
|
&&& \quad\text{ if }\val{V}{\env} = \Inl\, v \\ |
|
|
|
|
|
|
|
|
&\stepsto& \ba[t]{@{~}l}\cek{ M \mid \env[x \mapsto v] \mid \sigma},\\ |
|
|
|
|
|
\quad\text{ if }\val{V}{\env} = \Inl\, v\ea \\ |
|
|
|
|
|
|
|
|
% Case right |
|
|
% Case right |
|
|
\mlab{CaseR} & \ba{@{}l@{}l@{}} |
|
|
\mlab{CaseR} & \ba{@{}l@{}l@{}} |
|
|
\cekl \Case\; V\, \{&\Inl\, x \mapsto M; \\ |
|
|
\cekl \Case\; V\, \{&\Inl\, x \mapsto M; \\ |
|
|
&\Inr\, y \mapsto N\} \mid \env \mid \sigma \cekr \\ |
|
|
&\Inr\, y \mapsto N\} \mid \env \mid \sigma \cekr \\ |
|
|
\ea |
|
|
\ea |
|
|
&\stepsto& \cek{ N \mid \env[y \mapsto v] \mid \sigma},\\ |
|
|
|
|
|
&&& \quad\text{ if }\val{V}{\env} = \Inr\, v \\ |
|
|
|
|
|
|
|
|
&\stepsto& \ba[t]{@{~}l}\cek{ N \mid \env[y \mapsto v] \mid \sigma},\\ |
|
|
|
|
|
\quad\text{ if }\val{V}{\env} = \Inr\, v \ea\\ |
|
|
|
|
|
|
|
|
% Let - eval M |
|
|
% Let - eval M |
|
|
\mlab{Let} & \cek{ \Let \; x \revto M \; \In \; N \mid \env \mid \sigma} |
|
|
\mlab{Let} & \cek{ \Let \; x \revto M \; \In \; N \mid \env \mid \sigma} |
|
|
&\stepsto& \cek{ M \mid \env \mid (\env,x,N) \cons \sigma} \\ |
|
|
&\stepsto& \cek{ M \mid \env \mid (\env,x,N) \cons \sigma} \\ |
|
|
|
|
|
|
|
|
% Return - let binding |
|
|
% Return - let binding |
|
|
\mlab{RetCont} &\cek{ \Return \; V \mid \env \mid (\env',x,N) \cons \sigma} |
|
|
|
|
|
|
|
|
\mlab{PureCont} &\cek{ \Return \; V \mid \env \mid (\env',x,N) \cons \sigma} |
|
|
&\stepsto& \cek{ N \mid \env'[x \mapsto \val{V}{\env}] \mid \sigma} \\ |
|
|
&\stepsto& \cek{ N \mid \env'[x \mapsto \val{V}{\env}] \mid \sigma} \\ |
|
|
|
|
|
|
|
|
\end{reductions} |
|
|
|
|
|
|
|
|
\ea |
|
|
|
|
|
\el |
|
|
|
|
|
\] |
|
|
|
|
|
|
|
|
\textbf{Value interpretation} |
|
|
|
|
|
|
|
|
\textbf{Value interpretation} $\qquad\qquad~~\,\val{-} : \ValCat \times \MEnvCat \to \MValCat$ |
|
|
\[ |
|
|
\[ |
|
|
\bl |
|
|
\bl |
|
|
\begin{eqs} |
|
|
\begin{eqs} |
|
|
\val{x}{\env} &=& \env(x) \\ |
|
|
|
|
|
\val{\Unit{}}{\env} &=& \Unit{} \\ |
|
|
|
|
|
|
|
|
\val{x}{\env} &\defas& \env(x) \\ |
|
|
|
|
|
\val{\Unit{}}{\env} &\defas& \Unit{} \\ |
|
|
\end{eqs} |
|
|
\end{eqs} |
|
|
\qquad\qquad\qquad |
|
|
|
|
|
|
|
|
\qquad\qquad |
|
|
\begin{eqs} |
|
|
\begin{eqs} |
|
|
\val{n}{\env} &=& n \\ |
|
|
|
|
|
\val{c}\env &=& c \\ |
|
|
|
|
|
|
|
|
\val{n}{\env} &\defas& n \\ |
|
|
|
|
|
\val{c}\env &\defas& c \\ |
|
|
\end{eqs} |
|
|
\end{eqs} |
|
|
\qquad\qquad\qquad |
|
|
|
|
|
|
|
|
\qquad\qquad |
|
|
\begin{eqs} |
|
|
\begin{eqs} |
|
|
\val{\lambda x^A.M}{\env} &=& (\env, \lambda x^A.M) \\ |
|
|
|
|
|
\val{\Rec\, f^{A \to B}\, x.M}{\env} &=& (\env, \Rec\,f^{A \to B}\, x.M) \\ |
|
|
|
|
|
|
|
|
\val{\lambda x^A.M}{\env} &\defas& (\env, \lambda x^A.M) \\ |
|
|
|
|
|
\val{\Rec\, f^{A \to B}\, x.M}{\env} &\defas& (\env, \Rec\,f^{A \to B}\, x.M) \\ |
|
|
\end{eqs} |
|
|
\end{eqs} |
|
|
\medskip \\ |
|
|
\medskip \\ |
|
|
\begin{eqs} |
|
|
\begin{eqs} |
|
|
\val{\Record{V, W}}{\env} &=& \Record{\val{V}{\env}, \val{W}{\env}} \\ |
|
|
|
|
|
|
|
|
\val{\Record{V, W}}{\env} &\defas& \Record{\val{V}{\env}, \val{W}{\env}} \\ |
|
|
\end{eqs} |
|
|
\end{eqs} |
|
|
\qquad\qquad\qquad |
|
|
|
|
|
|
|
|
\qquad\qquad |
|
|
\ba{@{}r@{~}c@{~}l@{}} |
|
|
\ba{@{}r@{~}c@{~}l@{}} |
|
|
\val{(\Inl\, V)^B}{\env} &=& (\Inl\; \val{V}{\env})^B \\ |
|
|
|
|
|
\val{(\Inr\, V)^A}{\env} &=& (\Inr\; \val{V}{\env})^A \\ |
|
|
|
|
|
|
|
|
\val{(\Inl\, V)^B}{\env} &\defas& (\Inl\; \val{V}{\env})^B \\ |
|
|
|
|
|
\val{(\Inr\, V)^A}{\env} &\defas& (\Inr\; \val{V}{\env})^A \\ |
|
|
\ea |
|
|
\ea |
|
|
\el |
|
|
\el |
|
|
\] |
|
|
\] |
|
|
@ -15714,14 +15753,14 @@ The machine is initialised by placing a term in a configuration |
|
|
alongside the empty environment ($\emptyset$) and identity |
|
|
alongside the empty environment ($\emptyset$) and identity |
|
|
pure continuation ($\nil$). |
|
|
pure continuation ($\nil$). |
|
|
% |
|
|
% |
|
|
The rules (\mlab{App}), (\mlab{Rec}), (\mlab{Const}), (\mlab{Split}), |
|
|
|
|
|
(\mlab{CaseL}), and (\mlab{CaseR}) eliminate values. |
|
|
|
|
|
|
|
|
The rules (\mlab{App}), (\mlab{AppRec}), (\mlab{Const}), |
|
|
|
|
|
(\mlab{Split}), (\mlab{CaseL}), and (\mlab{CaseR}) eliminate values. |
|
|
% |
|
|
% |
|
|
The (\mlab{Let}) rule extends the current pure continuation with let |
|
|
The (\mlab{Let}) rule extends the current pure continuation with let |
|
|
bindings. |
|
|
bindings. |
|
|
% |
|
|
% |
|
|
The (\mlab{RetCont}) rule extends the environment in the top frame of |
|
|
|
|
|
the pure continuation with a returned value. |
|
|
|
|
|
|
|
|
The (\mlab{PureCont}) rule pops the top frame of the pure continuation |
|
|
|
|
|
and extends the environment with the returned value. |
|
|
% |
|
|
% |
|
|
Given an input of a well-typed closed computation term $\typ{}{M : |
|
|
Given an input of a well-typed closed computation term $\typ{}{M : |
|
|
A}$, the machine will either diverge or return a value of type $A$. |
|
|
A}$, the machine will either diverge or return a value of type $A$. |
|
|
@ -15738,34 +15777,43 @@ $\BCalc$; most transitions correspond directly to $\beta$-reductions, |
|
|
but $\mlab{Let}$ performs an administrative step to bring the |
|
|
but $\mlab{Let}$ performs an administrative step to bring the |
|
|
computation $M$ into evaluation position. |
|
|
computation $M$ into evaluation position. |
|
|
% |
|
|
% |
|
|
We formally state and prove the correspondence in |
|
|
|
|
|
Appendix~\ref{sec:base-machine-correctness}, relying on an |
|
|
|
|
|
inverse map $\inv{-}$ from configurations to |
|
|
|
|
|
terms~\citep{HillerstromLA20}. |
|
|
|
|
|
|
|
|
The proof of correctness is similar to the proof of |
|
|
|
|
|
Theorem~\ref{thm:handler-simulation} and the required proof gadgetry |
|
|
|
|
|
is the same. The full details are published in Appendix A of |
|
|
|
|
|
\citet{HillerstromLL20a}. |
|
|
|
|
|
% We formally state and prove the correspondence in |
|
|
|
|
|
% Appendix~\ref{sec:base-machine-correctness}, relying on an |
|
|
|
|
|
% inverse map $\inv{-}$ from configurations to |
|
|
|
|
|
% terms~\citep{HillerstromLA20}. |
|
|
% |
|
|
% |
|
|
\newcommand{\contapp}[2]{#1 #2} |
|
|
\newcommand{\contapp}[2]{#1 #2} |
|
|
\newcommand{\contappp}[2]{#1(#2)} |
|
|
\newcommand{\contappp}[2]{#1(#2)} |
|
|
|
|
|
|
|
|
\subsection{Handler machine} |
|
|
\subsection{Handler machine} |
|
|
|
|
|
\label{sec:handler-machine} |
|
|
\newcommand{\HClosure}{\dec{HClo}} |
|
|
\newcommand{\HClosure}{\dec{HClo}} |
|
|
We now enrich the $\BPCF$ machine to a $\HPCF$ machine. |
|
|
|
|
|
% |
|
|
% |
|
|
We extend the syntax as follows. |
|
|
|
|
|
|
|
|
We now extend the $\BPCF$ machine with functionality to evaluate |
|
|
|
|
|
$\HPCF$ terms. The resulting machine is almost the same as the machine |
|
|
|
|
|
in Chapter~\ref{ch:abstract-machine}, though, this machine supports |
|
|
|
|
|
only deep handlers. |
|
|
|
|
|
% |
|
|
|
|
|
The syntax is extended as follows. |
|
|
% |
|
|
% |
|
|
{ |
|
|
{ |
|
|
\begin{syntax} |
|
|
\begin{syntax} |
|
|
\slab{Configurations} &\conf \in \Conf &::=& \cek{M \mid \env \mid \kappa}\\ |
|
|
\slab{Configurations} &\conf \in \Conf &::=& \cek{M \mid \env \mid \kappa}\\ |
|
|
\slab{Resumptions} &\rho \in \dec{Res} &::=& (\sigma, \chi)\\ |
|
|
\slab{Resumptions} &\rho \in \dec{Res} &::=& (\sigma, \chi)\\ |
|
|
\slab{Continuations} &\kappa \in \Cont &::=& \nil \mid \rho \cons \kappa\\ |
|
|
|
|
|
\slab{Handler\textrm{ }closures} &\chi \in \HClosure &::=& (\env, H) \\ |
|
|
|
|
|
\slab{Machine\textrm{ }values} &v, w \in \MVal &::=& \cdots \mid \rho \\ |
|
|
|
|
|
|
|
|
\slab{Continuations} &\kappa \in \MGContCat &::=& \nil \mid \rho \cons \kappa\\ |
|
|
|
|
|
\slab{Handler\textrm{ }closures} &\chi \in \MGFrameCat &::=& (\env, H) \\ |
|
|
|
|
|
\slab{Machine\textrm{ }values} &v, w \in \MValCat &::=& \cdots \mid \rho \\ |
|
|
\end{syntax}}% |
|
|
\end{syntax}}% |
|
|
% |
|
|
% |
|
|
The notion of configurations changes slightly in that the continuation |
|
|
The notion of configurations changes slightly in that the continuation |
|
|
component is replaced by a generalised continuation |
|
|
component is replaced by a generalised continuation |
|
|
$\kappa \in \Cont$~\cite{HillerstromLA20}; a continuation is now a |
|
|
|
|
|
list of resumptions. A resumption is a pair of a pure continuation (as |
|
|
|
|
|
in the base machine) and a handler closure ($\chi$). |
|
|
|
|
|
|
|
|
$\kappa \in \MGContCat$; a continuation is now a list of |
|
|
|
|
|
resumptions. A resumption is a pair of a pure continuation (as in the |
|
|
|
|
|
base machine) and a handler closure ($\chi$). |
|
|
% |
|
|
% |
|
|
A handler closure consists of an environment and a handler definition, |
|
|
A handler closure consists of an environment and a handler definition, |
|
|
where the former binds the free variables that occur in the latter. |
|
|
where the former binds the free variables that occur in the latter. |
|
|
@ -15776,7 +15824,7 @@ identity handler closure: |
|
|
% |
|
|
% |
|
|
{ |
|
|
{ |
|
|
\[ |
|
|
\[ |
|
|
\kappa_0 \defas [(\nil, (\emptyset, \{\Val\;x \mapsto x\}))] |
|
|
|
|
|
|
|
|
\kappa_0 \defas [(\nil, (\emptyset, \{\Return\;x \mapsto x\}))] |
|
|
\]}% |
|
|
\]}% |
|
|
% |
|
|
% |
|
|
Machine values are augmented to include resumptions as an operation |
|
|
Machine values are augmented to include resumptions as an operation |
|
|
@ -15786,7 +15834,7 @@ clause). |
|
|
% |
|
|
% |
|
|
|
|
|
|
|
|
The handler machine adds transition rules for handlers, and modifies |
|
|
The handler machine adds transition rules for handlers, and modifies |
|
|
$(\mlab{Let})$ and $(\mlab{RetCont})$ from the base machine to account |
|
|
|
|
|
|
|
|
$(\mlab{Let})$ and $(\mlab{PureCont})$ from the base machine to account |
|
|
for the richer continuation |
|
|
for the richer continuation |
|
|
structure. Figure~\ref{fig:abstract-machine-semantics-handlers} |
|
|
structure. Figure~\ref{fig:abstract-machine-semantics-handlers} |
|
|
depicts the new and modified rules. |
|
|
depicts the new and modified rules. |
|
|
@ -15794,10 +15842,10 @@ depicts the new and modified rules. |
|
|
The $(\mlab{Handle})$ rule pushes a handler closure along with an |
|
|
The $(\mlab{Handle})$ rule pushes a handler closure along with an |
|
|
empty pure continuation onto the continuation stack. |
|
|
empty pure continuation onto the continuation stack. |
|
|
% |
|
|
% |
|
|
The $(\mlab{RetHandler})$ rule transfers control to the success clause |
|
|
|
|
|
|
|
|
The $(\mlab{GenCont})$ rule transfers control to the success clause |
|
|
of the current handler once the pure continuation is empty. |
|
|
of the current handler once the pure continuation is empty. |
|
|
% |
|
|
% |
|
|
The $(\mlab{Handle-Op})$ rule transfers control to the matching |
|
|
|
|
|
|
|
|
The $(\mlab{Op})$ rule transfers control to the matching |
|
|
operation clause on the topmost handler, and during the process it |
|
|
operation clause on the topmost handler, and during the process it |
|
|
reifies the handler closure. Finally, the $(\mlab{Resume})$ rule |
|
|
reifies the handler closure. Finally, the $(\mlab{Resume})$ rule |
|
|
applies a reified handler closure, by pushing it onto the continuation |
|
|
applies a reified handler closure, by pushing it onto the continuation |
|
|
@ -15810,7 +15858,9 @@ value or it gets stuck on an unhandled operation. |
|
|
\raggedright |
|
|
\raggedright |
|
|
|
|
|
|
|
|
\textbf{Transition relation} |
|
|
\textbf{Transition relation} |
|
|
\begin{reductions} |
|
|
|
|
|
|
|
|
\[ |
|
|
|
|
|
\bl |
|
|
|
|
|
\ba{@{}l@{~}r@{~}c@{~}l@{~~}l@{}} |
|
|
% Resume resumption |
|
|
% Resume resumption |
|
|
\mlab{Resume} & \cek{ V\;W \mid \env \mid \kappa} |
|
|
\mlab{Resume} & \cek{ V\;W \mid \env \mid \kappa} |
|
|
&\stepsto& \cek{ \Return \; W \mid \env \mid (\sigma, \chi) \cons \kappa},\\ |
|
|
&\stepsto& \cek{ \Return \; W \mid \env \mid (\sigma, \chi) \cons \kappa},\\ |
|
|
@ -15821,7 +15871,7 @@ value or it gets stuck on an unhandled operation. |
|
|
&\stepsto& \cek{ M \mid \env \mid ((\env,x,N) \cons \sigma, \chi) \cons \kappa} \\ |
|
|
&\stepsto& \cek{ M \mid \env \mid ((\env,x,N) \cons \sigma, \chi) \cons \kappa} \\ |
|
|
|
|
|
|
|
|
% Apply (machine) continuation - let binding |
|
|
% Apply (machine) continuation - let binding |
|
|
\mlab{RetCont} &\cek{ \Return \; V \mid \env \mid ((\env',x,N) \cons \sigma, \chi) \cons \kappa} |
|
|
|
|
|
|
|
|
\mlab{PureCont} &\cek{ \Return \; V \mid \env \mid ((\env',x,N) \cons \sigma, \chi) \cons \kappa} |
|
|
&\stepsto& \cek{ N \mid \env'[x \mapsto \val{V}{\env}] \mid (\sigma, \chi) \cons \kappa} \\ |
|
|
&\stepsto& \cek{ N \mid \env'[x \mapsto \val{V}{\env}] \mid (\sigma, \chi) \cons \kappa} \\ |
|
|
|
|
|
|
|
|
% Handle |
|
|
% Handle |
|
|
@ -15829,21 +15879,23 @@ value or it gets stuck on an unhandled operation. |
|
|
&\stepsto& \cek{ M \mid \env \mid (\nil, (\env, H)) \cons \kappa} \\ |
|
|
&\stepsto& \cek{ M \mid \env \mid (\nil, (\env, H)) \cons \kappa} \\ |
|
|
|
|
|
|
|
|
% Return - handler |
|
|
% Return - handler |
|
|
\mlab{RetHandler} & \cek{ \Return \; V \mid \env \mid (\nil, (\env',H)) \cons \kappa} |
|
|
|
|
|
|
|
|
\mlab{GenCont} & \cek{ \Return \; V \mid \env \mid (\nil, (\env',H)) \cons \kappa} |
|
|
&\stepsto& \cek{ M \mid \env'[x \mapsto \val{V}{\env}] \mid \kappa},\\ |
|
|
&\stepsto& \cek{ M \mid \env'[x \mapsto \val{V}{\env}] \mid \kappa},\\ |
|
|
&&&\quad\text{ if } \hret = \{\Val\; x \mapsto M\} \\ |
|
|
&&&\quad\text{ if } \hret = \{\Val\; x \mapsto M\} \\ |
|
|
|
|
|
|
|
|
% Handle op |
|
|
% Handle op |
|
|
\mlab{Handle-Op} & \cek{ \Do \; \ell~V \mid \env \mid (\sigma, (\env', H)) \cons \kappa } |
|
|
|
|
|
|
|
|
\mlab{Op} & \cek{ \Do \; \ell~V \mid \env \mid (\sigma, (\env', H)) \cons \kappa } |
|
|
&\stepsto& \cek{ M \mid \env'[\bl |
|
|
&\stepsto& \cek{ M \mid \env'[\bl |
|
|
p \mapsto \val{V}\env, \\ |
|
|
p \mapsto \val{V}\env, \\ |
|
|
r \mapsto (\sigma, (\env', H))] \mid \kappa }, \\ |
|
|
r \mapsto (\sigma, (\env', H))] \mid \kappa }, \\ |
|
|
\el \\ |
|
|
\el \\ |
|
|
&&&\quad\bl |
|
|
&&&\quad\bl |
|
|
\text{ if } \ell : A \to B \in \Sigma\\ |
|
|
\text{ if } \ell : A \to B \in \Sigma\\ |
|
|
\text{ and } \hell = \{\ell\; p \; r \mapsto M\} |
|
|
|
|
|
\el\\ |
|
|
|
|
|
\end{reductions} |
|
|
|
|
|
|
|
|
\text{ and } \hell = \{\OpCase{\ell}{p}{r} \mapsto M\} |
|
|
|
|
|
\el\\ |
|
|
|
|
|
\ea |
|
|
|
|
|
\el |
|
|
|
|
|
\] |
|
|
\caption{Abstract machine semantics for $\HPCF$.} |
|
|
\caption{Abstract machine semantics for $\HPCF$.} |
|
|
\label{fig:abstract-machine-semantics-handlers} |
|
|
\label{fig:abstract-machine-semantics-handlers} |
|
|
\end{figure*} |
|
|
\end{figure*} |
|
|
@ -15853,15 +15905,17 @@ value or it gets stuck on an unhandled operation. |
|
|
The handler machine faithfully simulates the operational semantics of |
|
|
The handler machine faithfully simulates the operational semantics of |
|
|
$\HPCF$. |
|
|
$\HPCF$. |
|
|
% |
|
|
% |
|
|
Extending the result for the base machine, we formally state and prove |
|
|
|
|
|
the correspondence in |
|
|
|
|
|
Appendix~\ref{sec:handler-machine-correctness}. |
|
|
|
|
|
|
|
|
The proof of correctness is almost a carbon copy of the proof of |
|
|
|
|
|
Theorem~\ref{thm:handler-simulation}. The full details are published |
|
|
|
|
|
in Appendix B of \citet{HillerstromLL20a}.% Extending the result for |
|
|
|
|
|
% the base machine, we formally state and prove the correspondence in |
|
|
|
|
|
% Appendix~\ref{sec:handler-machine-correctness}. |
|
|
|
|
|
|
|
|
\subsection{Realisability and Asymptotic Complexity} |
|
|
|
|
|
|
|
|
\subsection{Realisability and asymptotic complexity} |
|
|
\label{sec:realisability} |
|
|
\label{sec:realisability} |
|
|
As witnessed by the work of \citet{HillerstromL18} the machine |
|
|
|
|
|
structures are readily realisable using standard persistent functional |
|
|
|
|
|
data structures. |
|
|
|
|
|
|
|
|
As discussed in Section~\ref{subsec:machine-realisability} the machine |
|
|
|
|
|
is readily realisable using standard persistent functional data |
|
|
|
|
|
structures. |
|
|
% |
|
|
% |
|
|
Pure continuations on the base machine and generalised continuations |
|
|
Pure continuations on the base machine and generalised continuations |
|
|
on the handler machine can be implemented using linked lists with a |
|
|
on the handler machine can be implemented using linked lists with a |
|
|
@ -18027,6 +18081,22 @@ However, the effectful implementation runs between 2 and 14 times as |
|
|
fast with SML/NJ compared with MLton. |
|
|
fast with SML/NJ compared with MLton. |
|
|
|
|
|
|
|
|
\section{Related work} |
|
|
\section{Related work} |
|
|
|
|
|
Relatively few results of character of the result in this chapter have |
|
|
|
|
|
thus far been established in literature. \citet{Pippenger96} gives an |
|
|
|
|
|
example of an `online' operation on infinite sequences of atomic |
|
|
|
|
|
symbols (essentially a function from streams to streams) such that the |
|
|
|
|
|
first $n$ output symbols can be produced within time $\BigO(n)$ if one |
|
|
|
|
|
is working in an effectful version of Lisp (one which allows mutation |
|
|
|
|
|
of cons pairs) but with a worst-case runtime no better than |
|
|
|
|
|
$\Omega(n \log n)$ for any implementation in pure Lisp (without such |
|
|
|
|
|
mutation). This example was reconsidered by \citet{BirdJdM97} who |
|
|
|
|
|
showed that the same speedup can be achieved in a pure language by |
|
|
|
|
|
using lazy evaluation. \citet{Jones01} explores the approach of |
|
|
|
|
|
manifesting expressivity and efficiency differences between certain |
|
|
|
|
|
languages by artificially restricting attention to `cons-free' |
|
|
|
|
|
programs; in this setting, the classes of representable first-order |
|
|
|
|
|
functions for the various languages are found to coincide with some |
|
|
|
|
|
well-known complexity classes. |
|
|
|
|
|
|
|
|
\part{Conclusions} |
|
|
\part{Conclusions} |
|
|
\label{p:conclusions} |
|
|
\label{p:conclusions} |
|
|
|