1
0
mirror of https://github.com/dhil/phd-dissertation synced 2026-03-13 11:08:25 +00:00

Tidy up HO translation.

This commit is contained in:
2020-08-03 01:50:23 +01:00
parent 9c4eed2e94
commit b9aea3fab9

View File

@@ -860,8 +860,9 @@ given term.
The function computes the set of free variables bottom-up. Most cases The function computes the set of free variables bottom-up. Most cases
are homomorphic on the syntax constructors. The interesting cases are are homomorphic on the syntax constructors. The interesting cases are
those constructs which feature term binders: lambda abstraction, let those constructs which feature term binders: lambda abstraction, let
bindings, pair destructing, and case splitting. In each of those cases bindings, pair deconstructing, and case splitting. In each of those
we subtract the relevant binder(s) from the set of free variables. cases we subtract the relevant binder(s) from the set of free
variables.
\subsection{Typing rules} \subsection{Typing rules}
\label{sec:base-language-type-rules} \label{sec:base-language-type-rules}
@@ -1007,7 +1008,7 @@ application $V\,A$ is well-typed whenever the abstractor term $V$ has
the polymorphic type $\forall \alpha^K.C$ and the type $A$ has kind the polymorphic type $\forall \alpha^K.C$ and the type $A$ has kind
$K$. This rule makes use of type substitution. $K$. This rule makes use of type substitution.
% %
The \tylab{Split} rule handles typing of record destructing. When The \tylab{Split} rule handles typing of record deconstructing. When
splitting a record term $V$ on some label $\ell$ binding it to $x$ and splitting a record term $V$ on some label $\ell$ binding it to $x$ and
the remainder to $y$. The label we wish to split on must be present the remainder to $y$. The label we wish to split on must be present
with some type $A$, hence we require that with some type $A$, hence we require that
@@ -1566,9 +1567,9 @@ effect handlers which are an alternative to deep effect handlers.
% %
Programming with effect handlers is a dichotomy of \emph{performing} Programming with effect handlers is a dichotomy of \emph{performing}
and \emph{handling} of effectful operations -- or alternatively a and \emph{handling} of effectful operations -- or alternatively a
dichotomy of \emph{constructing} and \emph{destructing}. An operation dichotomy of \emph{constructing} and \emph{deconstructing}. An operation
is a constructor of an effect without a predefined semantics. A is a constructor of an effect without a predefined semantics. A
handler destructs effects by pattern-matching on their operations. By handler deconstructs effects by pattern-matching on their operations. By
matching on a particular operation, a handler instantiates the said matching on a particular operation, a handler instantiates the said
operation with a particular semantics of its own choosing. The key operation with a particular semantics of its own choosing. The key
ingredient to make this work in practice is \emph{delimited ingredient to make this work in practice is \emph{delimited
@@ -2534,28 +2535,12 @@ operation clauses extract and convert the current resumption stack
into a function using the $\Res$, and $\hforward$ augments the current into a function using the $\Res$, and $\hforward$ augments the current
resumption stack with the current continuation pair. resumption stack with the current continuation pair.
% %
% Since we have only changed the representation of resumptions, the
% translation of top-level programs remains the same.
\subsection{Higher-order translation for deep effect handlers} \subsection{Higher-order translation for deep effect handlers}
\label{sec:higher-order-uncurried-deep-handlers-cps} \label{sec:higher-order-uncurried-deep-handlers-cps}
% %
\begin{figure} \begin{figure}
% %
% \textbf{Static patterns and static lists}
% %
% \begin{syntax}
% \slab{Static patterns} &\sP& ::= & \sk \scons \sP \mid \sks \\
% \slab{Static lists} &\VS& ::= & V \scons \VS \mid \reflect V \\
% \end{syntax}
% %
% \textbf{Reification}
% %
% \begin{equations}
% \reify (V \scons \VS) &\defas& V \dcons \reify \VS \\
% \reify \reflect V &\defas& V \\
% \end{equations}
%
\textbf{Values} \textbf{Values}
% %
\begin{displaymath} \begin{displaymath}
@@ -2594,19 +2579,6 @@ resumption stack with the current continuation pair.
\cps{-} &:& \HandlerCat \to \UCompCat\\ \cps{-} &:& \HandlerCat \to \UCompCat\\
\cps{\{\Return \; x \mapsto N\}} &\defas& \dlam x\, ks.\Let\; (h \dcons ks') = ks \;\In\; \cps{N} \sapp \reflect ks' \cps{\{\Return \; x \mapsto N\}} &\defas& \dlam x\, ks.\Let\; (h \dcons ks') = ks \;\In\; \cps{N} \sapp \reflect ks'
\\ \\
% \cps{\{(\ell \; p \; r \mapsto N_\ell)_{\ell \in \mathcal{L}}\}}
% &\defas&
% \bl
% \dlam z \, ks.\Case \;z\; \{
% \bl
% (\ell~\Record{p, s} \mapsto \dLet\;r=\Fun\,s \;\dIn\; \cps{N_{\ell}} \sapp \reflect ks)_{\ell \in \mathcal{L}};\,
% y \mapsto \hforward \} \\
% \el \\
% \el \\
% \hforward &\defas& \bl
% \dLet\; (k' \dcons h' \dcons ks') = ks \;\dIn\; \\
% \Vmap\,(\dlam\Record{p, s}\,(k \dcons ks).k\,\Record{p, h' \dcons k' \dcons s}\,ks)\,y\,(h' \dcons ks') \\
% \el\\
\cps{\{(\ell \; p \; r \mapsto N_\ell)_{\ell \in \mathcal{L}}\}} \cps{\{(\ell \; p \; r \mapsto N_\ell)_{\ell \in \mathcal{L}}\}}
&\defas& \bl &\defas& \bl
\dlam \Record{z,\Record{p,rs}}\,ks.\Case \;z\; \{ \dlam \Record{z,\Record{p,rs}}\,ks.\Case \;z\; \{
@@ -2666,15 +2638,6 @@ alternating lists of pure continuation functions and effect
continuation functions. To ease notation we are going make use of continuation functions. To ease notation we are going make use of
pattern matching notation. The static meta language is generated by pattern matching notation. The static meta language is generated by
the following productions. the following productions.
% Static constructs are marked in
% {\color{blue}$\overline{\text{static blue}}$}, and their redexes are
% reduced as part of the translation (at compile time). We make use of
% static lambda abstractions, pairs, and lists. Reflection of dynamic
% language values into the static language is written as $\reflect V$.
% %
% We use $\shk$ for variables representing statically known
% continuations (frame stacks), $\shf$ for variables representing pure
% frame stacks, and $\chi$ for variables representing handlers.
% %
\begin{syntax} \begin{syntax}
\slab{Static patterns} &\sP \in \SPatCat &::=& \sks \mid \sk \scons \sP\\ \slab{Static patterns} &\sP \in \SPatCat &::=& \sks \mid \sk \scons \sP\\
@@ -2682,8 +2645,8 @@ the following productions.
\slab{Static computations} & \sM \in \SCompCat &::=& \sV \sapp \sW \mid \sV \dapp V \dapp W \slab{Static computations} & \sM \in \SCompCat &::=& \sV \sapp \sW \mid \sV \dapp V \dapp W
\end{syntax} \end{syntax}
% %
The patterns comprise only static list destructing. We let $\sP$ range The patterns comprise only static list deconstructing. We let $\sP$
over static patterns. range over static patterns.
% %
The static values comprise dynamic values, reflected dynamic values, The static values comprise dynamic values, reflected dynamic values,
static lists, and static lambda abstractions. We let $\sV, \sW$ range static lists, and static lambda abstractions. We let $\sV, \sW$ range
@@ -2706,8 +2669,8 @@ Static computations are subject to the following equational axioms.
The first equation is static $\beta$-equivalence, it states that The first equation is static $\beta$-equivalence, it states that
applying a static lambda abstraction with binder $\sks$ and body $\sM$ applying a static lambda abstraction with binder $\sks$ and body $\sM$
to a static value $\sV$ is equal to substituting $\sV$ for $\sks$ in to a static value $\sV$ is equal to substituting $\sV$ for $\sks$ in
$\sM$. The second equation allows us to apply a static list $\sM$. The second equation provides a means for applying a static
component-wise. lambda abstraction to a static list component-wise.
% %
\dhil{What about $\eta$-equivalence?} \dhil{What about $\eta$-equivalence?}
@@ -2720,32 +2683,38 @@ $\reify \sV$ by induction on their structure.
&\reify (\sV \scons \sW) \defas \reify \sV \dcons \reify \sW &\reify (\sV \scons \sW) \defas \reify \sV \dcons \reify \sW
\ea \ea
\] \]
%
\dhil{Need to spell out that static pattern matching may induce dynamic (administrative) reductions}
%
\paragraph{Higher-order translation} \paragraph{Higher-order translation}
The CPS translation is given in %
The complete CPS translation is given in
Figure~\ref{fig:cps-higher-order-uncurried}. In essence, it is the Figure~\ref{fig:cps-higher-order-uncurried}. In essence, it is the
same as the CPS translation for deep and shallow handlers we described same as the refined first-order uncurried CPS translation, although
in Section~\ref{sec:pure-as-stack}, albeit separated into static and the notation is slightly more involved due to the separation of static
dynamic parts. A major difference that has a large cosmetic effect on and dynamic parts.
the presentation of the translation is that we maintain the invariant
that the statically known stack ($\sk$) always contains at least one
frame, consisting of a triple
$\sRecord{\reflect V_{fs}, \sRecord{\reflect V_{ret}, \reflect
V_{ops}}}$ of reflected dynamic pure frame stacks, return
handlers, and operation handlers. Maintaining this invariant ensures
that all translations are uniform in whether they appear statically
within the scope of a handler or not, and this simplifies our
correctness proof. To maintain the invariant, any place where a
dynamically known stack is passed in (as a continuation parameter
$k$), it is immediately decomposed using a dynamic language $\Let$ and
repackaged as a static value with reflected variable
names. Unfortunately, this does add some clutter to the translation
definition, as compared to the translations above. However, there is a
payoff in the removal of administrative reductions at run time.
% %
\dhil{Rewrite the above.} The translation on values is mostly homomorphic on the syntax
constructors, except for $\lambda$- and $\Lambda$-abstractions which
are translated in the exact same way, because the target calculus has
no notion of types. As per usual continuation passing style practice,
the translation of a lambda abstraction yields a dynamic binary lambda
abstraction, where the second parameter is intended to be the
continuation parameter. However, the translation slightly diverge from
the usual practice in the translation of the body as the result of
$\cps{M}$ is applied statically, rather than dynamically, to the
(reflected) continuation parameter.
% %
The reason is that the translation on computations is staged: for any
given computation term the translation yields a static function, which
can be applied to a static continuation to ultimately produce a
$\UCalc$-computation term. This staging is key to eliminating static
administrative redexes as any static function may perform static
computation by manipulating its provided static continuation, as is
for instance done in the translation of $\Let$.
%
\dhil{Spell out why this translation qualifies as `higher-order'.}
Let us again revisit the example from Let us again revisit the example from
Section~\ref{sec:first-order-curried-cps} to see that the higher-order Section~\ref{sec:first-order-curried-cps} to see that the higher-order
translation eliminates the static redex at translation time. translation eliminates the static redex at translation time.
@@ -2758,15 +2727,19 @@ translation eliminates the static redex at translation time.
\end{equations} \end{equations}
% %
In contrast with the previous translations, the image of this In contrast with the previous translations, the image of this
translation admits only a single dynamic reduction. translation admits only a single dynamic reduction (disregarding the
dynamic administrative reductions arising from continuation
construction and deconstruction).
\subsubsection{Correctness} \subsubsection{Correctness}
\label{sec:higher-order-cps-deep-handlers-correctness} \label{sec:higher-order-cps-deep-handlers-correctness}
In order to prove the correctness of the higher-order uncurried CPS We establish the correctness of the higher-order uncurried CPS
translation (Theorem~\ref{thm:ho-simulation}), we first state several translation via a simulation result in style of
auxiliary lemmas describing how translated terms behave. First, the Plotkin~\cite{Plotkin75} (Theorem~\ref{thm:ho-simulation}). However,
higher-order CPS translation commutes with substitution. before we can state and prove this result, we first several auxiliary
lemmas describing how translated terms behave. First, the higher-order
CPS translation commutes with substitution.
% %
\begin{lemma}[Substitution]\label{lem:ho-cps-subst} \begin{lemma}[Substitution]\label{lem:ho-cps-subst}
% %
@@ -2811,8 +2784,8 @@ It follows as a corollary that top-level substitution is well-behaved.
Lemma~\ref{lem:ho-cps-subst}. Lemma~\ref{lem:ho-cps-subst}.
\end{proof} \end{proof}
% %
In order to reason about the behaviour of the \semlab{Op} rule, In order to reason about the behaviour \semlab{Op} rule, which is
which is defined in terms of an evaluation context, we extend the CPS defined in terms of an evaluation context, we need to extend the CPS
translation to evaluation contexts. translation to evaluation contexts.
% %
\begin{equations} \begin{equations}
@@ -2825,8 +2798,9 @@ translation to evaluation contexts.
The following lemma is the characteristic property of the CPS The following lemma is the characteristic property of the CPS
translation on evaluation contexts. translation on evaluation contexts.
% %
This allows us to focus on the computation contained within It provides a means for decomposing an evaluation context, such that
an evaluation context. we can focus on the computation contained within the evaluation
context.
% %
\begin{lemma}[Decomposition] \begin{lemma}[Decomposition]
\label{lem:decomposition} \label{lem:decomposition}
@@ -2841,26 +2815,27 @@ an evaluation context.
Proof by structural induction on the evaluation context $\EC$. Proof by structural induction on the evaluation context $\EC$.
\end{proof} \end{proof}
% %
Though we have eliminated the static administrative redexes, we are Even though we have eliminated the static administrative redexes, we
still left with one form of administrative redex that cannot be still need to account for the dynamic administrative redexes that
eliminated statically because it only appears at run-time. These arise arise from pattern matching against a reified continuation. To
from pattern matching against a reified stack of continuations and are properly account for these administrative redexes it is convenient to
given by the $\usemlab{SplitList}$ rule. treat list pattern matching as a primitive in $\UCalc$, therefore we
introduce a new reduction rule $\usemlab{SplitList}$ in $\UCalc$.
% %
\begin{reductions} \begin{reductions}
\usemlab{SplitList} & \Let\; (k \dcons ks) = V \dcons W \;\In\; M &\reducesto& M[V/k, W/ks] \\ \usemlab{SplitList} & \Let\; (k \dcons ks) = V \dcons W \;\In\; M &\reducesto& M[V/k, W/ks] \\
\end{reductions} \end{reductions}
% %
This is isomorphic to the \usemlab{Split} rule, but we now treat lists Note this rule is isomorphic to the \usemlab{Split} rule with lists
and \usemlab{SplitList} as distinct from pairs, unit, and encoded as right nested pairs using unit to denote nil.
\usemlab{Split} in the higher-order translation so that we can
properly account for administrative reduction.
% %
We write $\areducesto$ for the compatible closure of We write $\areducesto$ for the compatible closure of
\usemlab{SplitList}. \usemlab{SplitList}.
By definition, $\reify \reflect V = V$, but we also need to reason We also need to be able to reason about the computational content of
about the inverse composition. reflection after reification. By definition we have that
$\reify \reflect V = V$, the following lemma lets us reason about the
inverse composition.
% %
\begin{lemma}[Reflect after reify] \begin{lemma}[Reflect after reify]
\label{lem:reflect-after-reify} \label{lem:reflect-after-reify}
@@ -2917,10 +2892,10 @@ Follows from Lemmas~\ref{lem:decomposition},
\ref{lem:reflect-after-reify}, and \ref{lem:forwarding}. \ref{lem:reflect-after-reify}, and \ref{lem:forwarding}.
\end{proof} \end{proof}
% %
We now turn to our main result which is a simulation result in style Finally, we have the ingredients to state and prove the simulation
of Plotkin~\cite{Plotkin75}. The theorem shows that the only extra result. The following theorem shows that the only extra behaviour
behaviour exhibited by a translated term is the bureaucracy of exhibited by a translated term is the bureaucracy of deconstructing
deconstructing the continuation stack. the continuation stack.
% %
\begin{theorem}[Simulation] \begin{theorem}[Simulation]
\label{thm:ho-simulation} \label{thm:ho-simulation}
@@ -2933,18 +2908,18 @@ If $M \reducesto N$ then $\pcps{M} \reducesto^+ \areducesto^* \pcps{N}$.
follows from Lemma~\ref{lem:handle-op}. follows from Lemma~\ref{lem:handle-op}.
\end{proof} \end{proof}
% %
In common with most CPS translations, full abstraction does not % In common with most CPS translations, full abstraction does not
hold. However, as our semantics is deterministic it is straightforward % hold. However, as our semantics is deterministic it is straightforward
to show a backward simulation result. % to show a backward simulation result.
% % %
\begin{corollary}[Backwards simulation] % \begin{corollary}[Backwards simulation]
If $\pcps{M} \reducesto^+ \areducesto^* V$ then there exists $W$ such that % If $\pcps{M} \reducesto^+ \areducesto^* V$ then there exists $W$ such that
$M \reducesto^* W$ and $\pcps{W} = V$. % $M \reducesto^* W$ and $\pcps{W} = V$.
\end{corollary} % \end{corollary}
% % %
\begin{proof} % \begin{proof}
TODO\dots % TODO\dots
\end{proof} % \end{proof}
% %
\chapter{Abstract machine semantics} \chapter{Abstract machine semantics}