|
@@ -58,7 +58,7 @@ showstringspaces=false
|
|
\lstset{%
|
|
\lstset{%
|
|
language=Python,
|
|
language=Python,
|
|
basicstyle=\ttfamily\small,
|
|
basicstyle=\ttfamily\small,
|
|
-morekeywords={match,case,bool,int},
|
|
|
|
|
|
+morekeywords={match,case,bool,int,let},
|
|
deletekeywords={},
|
|
deletekeywords={},
|
|
escapechar=|,
|
|
escapechar=|,
|
|
columns=flexible,
|
|
columns=flexible,
|
|
@@ -15350,33 +15350,45 @@ def g(x_0 : int)-> int:
|
|
\label{sec:closure-conversion}
|
|
\label{sec:closure-conversion}
|
|
\index{subject}{closure conversion}
|
|
\index{subject}{closure conversion}
|
|
|
|
|
|
-\python{UNDER CONSTRUCTION}
|
|
|
|
-
|
|
|
|
The compiling of lexically-scoped functions into top-level function
|
|
The compiling of lexically-scoped functions into top-level function
|
|
-definitions is accomplished in the pass \code{convert-to-closures}
|
|
|
|
|
|
+definitions is accomplished in the pass \code{convert\_to\_closures}
|
|
that comes after \code{reveal\_functions} and before
|
|
that comes after \code{reveal\_functions} and before
|
|
-\code{limit-functions}.
|
|
|
|
|
|
+\code{limit\_functions}.
|
|
|
|
|
|
As usual, we implement the pass as a recursive function over the
|
|
As usual, we implement the pass as a recursive function over the
|
|
-AST. All of the action is in the cases for \key{Lambda} and
|
|
|
|
-\key{Apply}. We transform a \key{Lambda} expression into an expression
|
|
|
|
-that creates a closure, that is, a vector whose first element is a
|
|
|
|
-function pointer and the rest of the elements are the free variables
|
|
|
|
-of the \key{Lambda}. We use the struct \code{Closure} here instead of
|
|
|
|
-using \code{vector} so that we can distinguish closures from vectors
|
|
|
|
-in Section~\ref{sec:optimize-closures} and to record the arity. In
|
|
|
|
-the generated code below, the \itm{name} is a unique symbol generated
|
|
|
|
-to identify the function and the \itm{arity} is the number of
|
|
|
|
-parameters (the length of \itm{ps}).
|
|
|
|
|
|
+AST. The interesting cases are the ones for \key{lambda} and function
|
|
|
|
+application. We transform a \key{lambda} expression into an expression
|
|
|
|
+that creates a closure, that is, a tuple whose first element is a
|
|
|
|
+function pointer and the rest of the elements are the values of the
|
|
|
|
+free variables of the \key{lambda}. However, we use the \code{Closure}
|
|
|
|
+AST node instead of using a tuple so that we can record the arity and
|
|
|
|
+to distinguish closures from tuples in
|
|
|
|
+Section~\ref{sec:optimize-closures}. In the generated code below,
|
|
|
|
+\itm{fvs} is the free variables of the lambda, \itm{name} is a unique
|
|
|
|
+symbol generated to identify the lambda and the \itm{arity} is the
|
|
|
|
+number of parameters (the length of \itm{ps}).
|
|
|
|
+%
|
|
|
|
+{\if\edition\racketEd
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
(Lambda |\itm{ps}| |\itm{rt}| |\itm{body}|)
|
|
(Lambda |\itm{ps}| |\itm{rt}| |\itm{body}|)
|
|
|$\Rightarrow$|
|
|
|$\Rightarrow$|
|
|
(Closure |\itm{arity}| (cons (FunRef |\itm{name}|) |\itm{fvs}|))
|
|
(Closure |\itm{arity}| (cons (FunRef |\itm{name}|) |\itm{fvs}|))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
-In addition to transforming each \key{Lambda} into a \key{Closure}, we
|
|
|
|
-create a top-level function definition for each \key{Lambda}, as
|
|
|
|
-shown below.\\
|
|
|
|
|
|
+\fi}
|
|
|
|
+%
|
|
|
|
+{\if\edition\pythonEd
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+Lambda(|\itm{ps}|, |\itm{body}|)
|
|
|
|
+|$\Rightarrow$|
|
|
|
|
+Closure(|\itm{arity}|, [FunRef(|\itm{name}|), |\itm{fvs}, \ldots|])
|
|
|
|
+\end{lstlisting}
|
|
|
|
+\fi}
|
|
|
|
+%
|
|
|
|
+In addition to transforming each \key{Lambda} AST node into a
|
|
|
|
+\key{Closure}, we create a top-level function definition for each
|
|
|
|
+\key{Lambda}, as shown below.\\
|
|
\begin{minipage}{0.8\textwidth}
|
|
\begin{minipage}{0.8\textwidth}
|
|
|
|
+{\if\edition\racketEd
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
(Def |\itm{name}| ([clos : (Vector _ |\itm{fvts}| ...)] |\itm{ps'}| ...) |\itm{rt'}|
|
|
(Def |\itm{name}| ([clos : (Vector _ |\itm{fvts}| ...)] |\itm{ps'}| ...) |\itm{rt'}|
|
|
(Let |$\itm{fvs}_1$| (Prim 'vector-ref (list (Var clos) (Int 1)))
|
|
(Let |$\itm{fvs}_1$| (Prim 'vector-ref (list (Var clos) (Int 1)))
|
|
@@ -15384,64 +15396,117 @@ shown below.\\
|
|
(Let |$\itm{fvs}_n$| (Prim 'vector-ref (list (Var clos) (Int |$n$|)))
|
|
(Let |$\itm{fvs}_n$| (Prim 'vector-ref (list (Var clos) (Int |$n$|)))
|
|
|\itm{body'}|)...))
|
|
|\itm{body'}|)...))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
|
|
+\fi}
|
|
|
|
+{\if\edition\pythonEd
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+def |\itm{name}|(clos : |\itm{closTy}|, |\itm{ps'}, \ldots|) -> |\itm{rt'}|:
|
|
|
|
+ |$\itm{fvs}_1$| = clos[1]
|
|
|
|
+ |$\ldots$|
|
|
|
|
+ |$\itm{fvs}_n$| = clos[|$n$|]
|
|
|
|
+ |\itm{body'}|
|
|
|
|
+\end{lstlisting}
|
|
|
|
+\fi}
|
|
\end{minipage}\\
|
|
\end{minipage}\\
|
|
The \code{clos} parameter refers to the closure. Translate the type
|
|
The \code{clos} parameter refers to the closure. Translate the type
|
|
annotations in \itm{ps} and the return type \itm{rt}, as discussed in
|
|
annotations in \itm{ps} and the return type \itm{rt}, as discussed in
|
|
-the next paragraph, to obtain \itm{ps'} and \itm{rt'}. The types
|
|
|
|
-$\itm{fvts}$ are the types of the free variables in the lambda and the
|
|
|
|
-underscore \code{\_} is a dummy type that we use because it is rather
|
|
|
|
-difficult to give a type to the function in the closure's
|
|
|
|
-type.\footnote{To give an accurate type to a closure, we would need to
|
|
|
|
- add existential types to the type checker~\citep{Minamide:1996ys}.}
|
|
|
|
-The dummy type is considered to be equal to any other type during type
|
|
|
|
-checking. The sequence of \key{Let} forms bind the free variables to
|
|
|
|
-their values obtained from the closure.
|
|
|
|
-
|
|
|
|
-Closure conversion turns functions into vectors, so the type
|
|
|
|
|
|
+the next paragraph, to obtain \itm{ps'} and \itm{rt'}. The type
|
|
|
|
+\itm{closTy} is a tuple type whose first element type is
|
|
|
|
+\python{\code{Bottom()}}\racket{\code{\_} (the dummy type)} and the rest of
|
|
|
|
+the element types are the types of the free variables in the
|
|
|
|
+lambda. We use \python{\code{Bottom()}}\racket{\code{\_}} because it
|
|
|
|
+is difficult to give a type to the function in the closure's type.%
|
|
|
|
+%
|
|
|
|
+\footnote{To give an accurate type to a closure, we would need to add
|
|
|
|
+ existential types to the type checker~\citep{Minamide:1996ys}.}
|
|
|
|
+%
|
|
|
|
+%% The dummy type is considered to be equal to any other type during type
|
|
|
|
+%% checking.
|
|
|
|
+The free variables become local variables that are initialized with
|
|
|
|
+their values in the closure.
|
|
|
|
+
|
|
|
|
+Closure conversion turns every function into a tuple, so the type
|
|
annotations in the program must also be translated. We recommend
|
|
annotations in the program must also be translated. We recommend
|
|
-defining a auxiliary recursive function for this purpose. Function
|
|
|
|
|
|
+defining an auxiliary recursive function for this purpose. Function
|
|
types should be translated as follows.
|
|
types should be translated as follows.
|
|
|
|
+%
|
|
|
|
+{\if\edition\racketEd
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
(|$T_1, \ldots, T_n$| -> |$T_r$|)
|
|
(|$T_1, \ldots, T_n$| -> |$T_r$|)
|
|
|$\Rightarrow$|
|
|
|$\Rightarrow$|
|
|
-(Vector ((Vector _) |$T'_1, \ldots, T'_n$| -> |$T'_r$|))
|
|
|
|
|
|
+(Vector ((Vector) |$T'_1, \ldots, T'_n$| -> |$T'_r$|))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
-The above type says that the first thing in the vector is a function
|
|
|
|
-pointer. The first parameter of the function pointer is a vector (a
|
|
|
|
-closure) and the rest of the parameters are the ones from the original
|
|
|
|
-function, with types $T'_1, \ldots, T'_n$. The \code{Vector} type for
|
|
|
|
-the closure omits the types of the free variables because 1) those
|
|
|
|
-types are not available in this context and 2) we do not need them in
|
|
|
|
-the code that is generated for function application.
|
|
|
|
|
|
+\fi}
|
|
|
|
+{\if\edition\pythonEd
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+FunctionType([|$T_1, \ldots, T_n$|], |$T_r$|)
|
|
|
|
+|$\Rightarrow$|
|
|
|
|
+TupleType([FunctionType([TupleType([]), |$T'_1, \ldots, T'_n$|], |$T'_r$|)])
|
|
|
|
+\end{lstlisting}
|
|
|
|
+\fi}
|
|
|
|
+%
|
|
|
|
+The above type says that the first thing in the tuple is a
|
|
|
|
+function. The first parameter of the function is a tuple (a closure)
|
|
|
|
+and the rest of the parameters are the ones from the original
|
|
|
|
+function, with types $T'_1, \ldots, T'_n$. The type for the closure
|
|
|
|
+omits the types of the free variables because 1) those types are not
|
|
|
|
+available in this context and 2) we do not need them in the code that
|
|
|
|
+is generated for function application.
|
|
|
|
|
|
We transform function application into code that retrieves the
|
|
We transform function application into code that retrieves the
|
|
-function pointer from the closure and then calls the function, passing
|
|
|
|
-in the closure as the first argument. We bind $e'$ to a temporary
|
|
|
|
-variable to avoid code duplication.
|
|
|
|
|
|
+function from the closure and then calls the function, passing in the
|
|
|
|
+closure as the first argument. We place $e'$ in a temporary variable
|
|
|
|
+to avoid code duplication.
|
|
|
|
+%
|
|
|
|
+{\if\edition\racketEd
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
-(Apply |$e$| |\itm{es}|)
|
|
|
|
|
|
+(Apply |$e$| |$\itm{es}$|)
|
|
|$\Rightarrow$|
|
|
|$\Rightarrow$|
|
|
-(Let |\itm{tmp}| |$e'$|
|
|
|
|
- (Apply (Prim 'vector-ref (list (Var |\itm{tmp}|) (Int 0))) (cons |\itm{tmp}| |\itm{es'}|)))
|
|
|
|
|
|
+(Let |$\itm{tmp}$| |$e'$|
|
|
|
|
+ (Apply (Prim 'vector-ref (list (Var |$\itm{tmp}$|) (Int 0))) (cons |$\itm{tmp}$| |$\itm{es'}$|)))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
|
|
+\fi}
|
|
|
|
+%
|
|
|
|
+{\if\edition\pythonEd
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+Call(|$e$|, [|$e_1, \ldots, e_n$|])
|
|
|
|
+|$\Rightarrow$|
|
|
|
|
+Let(|$\itm{tmp}$|, |$e'$|,
|
|
|
|
+ Call(Subscript(Name(|$\itm{tmp}$|), Constant(0)),
|
|
|
|
+ [|$\itm{tmp}$|, |$e'_1, \ldots, e'_n$|]))
|
|
|
|
+\end{lstlisting}
|
|
|
|
+\fi}
|
|
|
|
|
|
-There is also the question of what to do with references top-level
|
|
|
|
|
|
+There is also the question of what to do with references to top-level
|
|
function definitions. To maintain a uniform translation of function
|
|
function definitions. To maintain a uniform translation of function
|
|
application, we turn function references into closures.
|
|
application, we turn function references into closures.
|
|
|
|
|
|
\begin{tabular}{lll}
|
|
\begin{tabular}{lll}
|
|
\begin{minipage}{0.3\textwidth}
|
|
\begin{minipage}{0.3\textwidth}
|
|
|
|
+{\if\edition\racketEd
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
(FunRefArity |$f$| |$n$|)
|
|
(FunRefArity |$f$| |$n$|)
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
|
|
+\fi}
|
|
|
|
+{\if\edition\pythonEd
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+FunRefArity(|$f$|, |$n$|)
|
|
|
|
+\end{lstlisting}
|
|
|
|
+\fi}
|
|
\end{minipage}
|
|
\end{minipage}
|
|
&
|
|
&
|
|
$\Rightarrow$
|
|
$\Rightarrow$
|
|
&
|
|
&
|
|
\begin{minipage}{0.5\textwidth}
|
|
\begin{minipage}{0.5\textwidth}
|
|
|
|
+{\if\edition\racketEd
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
(Closure |$n$| (FunRef |$f$|) '())
|
|
(Closure |$n$| (FunRef |$f$|) '())
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
|
|
+\fi}
|
|
|
|
+{\if\edition\pythonEd
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+Closure(|$n$|, [FunRef(|$f$|)])
|
|
|
|
+\end{lstlisting}
|
|
|
|
+\fi}
|
|
\end{minipage}
|
|
\end{minipage}
|
|
\end{tabular} \\
|
|
\end{tabular} \\
|
|
%
|
|
%
|
|
@@ -15452,13 +15517,14 @@ an extra closure parameter.
|
|
\label{sec:example-lambda}
|
|
\label{sec:example-lambda}
|
|
|
|
|
|
Figure~\ref{fig:lexical-functions-example} shows the result of
|
|
Figure~\ref{fig:lexical-functions-example} shows the result of
|
|
-\code{reveal\_functions} and \code{convert-to-closures} for the example
|
|
|
|
|
|
+\code{reveal\_functions} and \code{convert\_to\_closures} for the example
|
|
program demonstrating lexical scoping that we discussed at the
|
|
program demonstrating lexical scoping that we discussed at the
|
|
beginning of this chapter.
|
|
beginning of this chapter.
|
|
|
|
|
|
|
|
|
|
\begin{figure}[tbp]
|
|
\begin{figure}[tbp]
|
|
\begin{minipage}{0.8\textwidth}
|
|
\begin{minipage}{0.8\textwidth}
|
|
|
|
+{\if\edition\racketEd
|
|
% tests/lambda_test_6.rkt
|
|
% tests/lambda_test_6.rkt
|
|
\begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
|
|
\begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
|
|
(define (f6 [x7 : Integer]) : (Integer -> Integer)
|
|
(define (f6 [x7 : Integer]) : (Integer -> Integer)
|
|
@@ -15489,8 +15555,40 @@ $\Rightarrow$
|
|
((vector-ref clos6 0) clos6 3))])
|
|
((vector-ref clos6 0) clos6 3))])
|
|
(+ ((vector-ref g0 0) g0 11) ((vector-ref h1 0) h1 15)))))
|
|
(+ ((vector-ref g0 0) g0 11) ((vector-ref h1 0) h1 15)))))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
-\end{minipage}
|
|
|
|
|
|
+\fi}
|
|
|
|
+%
|
|
|
|
+{\if\edition\pythonEd
|
|
|
|
+% free_var.py
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+def f(x : int) -> Callable[[int], int]:
|
|
|
|
+ y = 4
|
|
|
|
+ return lambda z: x + y + z
|
|
|
|
+
|
|
|
|
+g = f(5)
|
|
|
|
+h = f(3)
|
|
|
|
+print( g(11) + h(15) )
|
|
|
|
+\end{lstlisting}
|
|
|
|
+$\Rightarrow$
|
|
|
|
+\begin{lstlisting}
|
|
|
|
+def lambda_0(fvs_1:tuple[bot,int,tuple[int]],z:int) -> int:
|
|
|
|
+ x = fvs_1[1]
|
|
|
|
+ y = fvs_1[2]
|
|
|
|
+ return x + y[0] + z
|
|
|
|
+
|
|
|
|
+def f(fvs_2:bot, x:int) -> tuple[Callable[[tuple[],int], int]]
|
|
|
|
+ y = (777,)
|
|
|
|
+ y[0] = 4
|
|
|
|
+ return closure(lambda_0,y,x)
|
|
|
|
|
|
|
|
+def main() -> int:
|
|
|
|
+ g = (let clos_3 = closure(f) in clos_3[0](clos_3, 5))
|
|
|
|
+ h = (let clos_4 = closure(f) in clos_4[0](clos_4, 3))
|
|
|
|
+ print((let clos_5 = g in clos_5[0](clos_5, 11))
|
|
|
|
+ + (let clos_6 = h in clos_6[0](clos_6, 15)))
|
|
|
|
+ return 0
|
|
|
|
+\end{lstlisting}
|
|
|
|
+\fi}
|
|
|
|
+\end{minipage}
|
|
\caption{Example of closure conversion.}
|
|
\caption{Example of closure conversion.}
|
|
\label{fig:lexical-functions-example}
|
|
\label{fig:lexical-functions-example}
|
|
\end{figure}
|
|
\end{figure}
|
|
@@ -15545,6 +15643,9 @@ operators.
|
|
\end{array}
|
|
\end{array}
|
|
\]
|
|
\]
|
|
\fi}
|
|
\fi}
|
|
|
|
+{\if\edition\pythonEd
|
|
|
|
+UNDER CONSTRUCTION
|
|
|
|
+\fi}
|
|
\end{minipage}
|
|
\end{minipage}
|
|
}
|
|
}
|
|
\caption{The abstract syntax of \LangCLam{}, extending \LangCFun{} (Figure~\ref{fig:c3-syntax}).}
|
|
\caption{The abstract syntax of \LangCLam{}, extending \LangCFun{} (Figure~\ref{fig:c3-syntax}).}
|