瀏覽代碼

more progress on closure conversion

Jeremy Siek 3 年之前
父節點
當前提交
7e3e559550
共有 2 個文件被更改,包括 244 次插入148 次删除
  1. 241 147
      book.tex
  2. 3 1
      defs.tex

+ 241 - 147
book.tex

@@ -12818,12 +12818,12 @@ type, written
 \fi}
 \fi}
 {\if\edition\pythonEd
 {\if\edition\pythonEd
 \begin{lstlisting}
 \begin{lstlisting}
-   Callable[[|$\Type_1$|,|$\cdots$|,|$\Type_n$|], |$\Type_r$|]
+   Callable[[|$\Type_1$|,|$\cdots$|,|$\Type_n$|], |$\Type_R$|]
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
 %
 %
 \noindent for a function whose $n$ parameters have the types $\Type_1$
 \noindent for a function whose $n$ parameters have the types $\Type_1$
-through $\Type_n$ and whose return type is $\Type_r$. The main
+through $\Type_n$ and whose return type is $\Type_R$. The main
 limitation of these functions (with respect to
 limitation of these functions (with respect to
 \racket{Racket}\python{Python} functions) is that they are not
 \racket{Racket}\python{Python} functions) is that they are not
 lexically scoped. That is, the only external entities that can be
 lexically scoped. That is, the only external entities that can be
@@ -12859,7 +12859,8 @@ nested inside each other.
     \Type &::=& \key{FunctionType}\LP \Type^{*} \key{, } \Type \RP \\
     \Type &::=& \key{FunctionType}\LP \Type^{*} \key{, } \Type \RP \\
     \Exp &::=& \CALL{\Exp}{\Exp^{*}}\\
     \Exp &::=& \CALL{\Exp}{\Exp^{*}}\\
     \Stmt &::=& \RETURN{\Exp} \\
     \Stmt &::=& \RETURN{\Exp} \\
-   \Def &::=& \FUNDEF{\Var}{\LS \LP \Var \key{, } \Type \RP \key{, } \ldots \RS}{\Type}{}{\Stmt^{+}} 
+   \Params &::=& \LS\LP\Var\key{,}\Type\RP\code{,}\ldots\RS \\
+   \Def &::=& \FUNDEF{\Var}{\Params}{\Type}{}{\Stmt^{+}} 
   \end{array}
   \end{array}
 }
 }
 
 
@@ -12893,7 +12894,7 @@ nested inside each other.
   \gray{\LtupGrammarPython} \\  \hline
   \gray{\LtupGrammarPython} \\  \hline
   \LfunGrammarPython \\
   \LfunGrammarPython \\
 \begin{array}{rcl}
 \begin{array}{rcl}
-  \LangFunM{} &::=& \Def^{*} \Stmt^{*}
+  \LangFunM{} &::=& \Def\ldots \Stmt\ldots
 \end{array}
 \end{array}
 \end{array}
 \end{array}
 \]
 \]
@@ -12949,7 +12950,7 @@ nested inside each other.
 The program in Figure~\ref{fig:Rfun-function-example} is a
 The program in Figure~\ref{fig:Rfun-function-example} is a
 representative example of defining and using functions in \LangFun{}.
 representative example of defining and using functions in \LangFun{}.
 We define a function \code{map} that applies some other function
 We define a function \code{map} that applies some other function
-\code{f} to both elements of a vector and returns a new vector
+\code{f} to both elements of a tuple and returns a new tuple
 containing the results. We also define a function \code{inc}.  The
 containing the results. We also define a function \code{inc}.  The
 program applies \code{map} to \code{inc} and
 program applies \code{map} to \code{inc} and
 %
 %
@@ -13250,6 +13251,8 @@ class TypeCheckLfun(TypeCheckLtup):
 \end{figure}
 \end{figure}
 
 
 
 
+\clearpage
+
 \section{Functions in x86}
 \section{Functions in x86}
 \label{sec:fun-x86}
 \label{sec:fun-x86}
 
 
@@ -13535,7 +13538,7 @@ Module(|$\Def\ldots\Stmt\ldots$|)
 \end{lstlisting}
 \end{lstlisting}
 where $\itm{mainDef}$ is
 where $\itm{mainDef}$ is
 \begin{lstlisting}
 \begin{lstlisting}
-FunctionDef('main', [], int, |$\Stmt'\ldots$|Return(Constant(0)))
+FunctionDef('main', [], int, None, |$\Stmt'\ldots$|Return(Constant(0)), None)
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
 
 
@@ -13571,7 +13574,7 @@ defined in Figure~\ref{fig:f1-syntax}.
 \[
 \[
 \begin{array}{lcl}
 \begin{array}{lcl}
 \Exp &::=& \FUNREF{\Var}\\
 \Exp &::=& \FUNREF{\Var}\\
-  \LangFunM{} &::=& \PROGRAM{}{\LS \Def \code{,} \ldots \RS}
+  \LangFunRefM{} &::=& \PROGRAM{}{\LS \Def \code{,} \ldots \RS}
 \end{array}
 \end{array}
 \]
 \]
 \fi}
 \fi}
@@ -13620,9 +13623,10 @@ follows.
 \fi}
 \fi}
 {\if\edition\pythonEd   
 {\if\edition\pythonEd   
 \begin{lstlisting}
 \begin{lstlisting}
-  FunctionDef(|$f$|, [(|$x_1$|,|$T_1$|),|$\ldots$|,(|$x_n$|,|$T_n$|)], |$T_r$|, |$\itm{body}$|)
+  FunctionDef(|$f$|, [(|$x_1$|,|$T_1$|),|$\ldots$|,(|$x_n$|,|$T_n$|)], |$T_r$|, None, |$\itm{body}$|, None)
 |$\Rightarrow$|
 |$\Rightarrow$|
-  FunctionDef(|$f$|, [(|$x_1$|,|$T_1$|),|$\ldots$|,(|$x_5$|,|$T_5$|),(tup,TupleType([|$T_6, \ldots, T_n$|]))], |$T_r$|, |$\itm{body}'$|) 
+  FunctionDef(|$f$|, [(|$x_1$|,|$T_1$|),|$\ldots$|,(|$x_5$|,|$T_5$|),(tup,TupleType([|$T_6, \ldots, T_n$|]))],
+         |$T_r$|, None, |$\itm{body}'$|, None)
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
 %
 %
@@ -13783,9 +13787,12 @@ appropriate explicate functions for the various contexts.
 
 
 \newcommand{\CfunASTPython}{
 \newcommand{\CfunASTPython}{
 \begin{array}{lcl}
 \begin{array}{lcl}
-\Exp &::= & \FUNREF{\itm{label}} \MID \CALL{\Atm}{\LS\Atm\code{,}\ldots\RS} \\
-\Stmt &::= & \TAILCALL{\Atm}{\LS\Atm\code{,}\ldots\RS} \\
-\Def &::=& \DEF{\itm{label}}{\LS\LP\Var\key{,}\Type\RP\code{,}\ldots\RS}{\LC\itm{label}\key{:}\Stmt^{*}\code{,}\ldots\RC}{\_}{\Type}{\_} 
+\Exp &::= & \FUNREF{\itm{label}} \MID \CALL{\Atm}{\Atm^{*}} \\
+\Stmt &::= & \TAILCALL{\Atm}{\Atm^{*}} \\
+\Params &::=& \LS\LP\Var\key{,}\Type\RP\code{,}\ldots\RS \\
+\Block &::=& \Stmt^{*} \\
+\Blocks &::=& \LC\itm{label}\key{:}\Block\code{,}\ldots\RC \\
+\Def &::=& \DEF{\itm{label}}{\Params}{\Blocks}{\key{None}}{\Type}{\key{None}} 
 \end{array}
 \end{array}
 }
 }
 
 
@@ -13845,8 +13852,9 @@ language, whose syntax is defined in Figure~\ref{fig:x86-3}.
 \Instr &::=& \ldots
 \Instr &::=& \ldots
      \MID \key{callq}\;\key{*}\Arg \MID \key{tailjmp}\;\Arg 
      \MID \key{callq}\;\key{*}\Arg \MID \key{tailjmp}\;\Arg 
      \MID \key{leaq}\;\Arg\key{,}\;\key{\%}\Reg \\
      \MID \key{leaq}\;\Arg\key{,}\;\key{\%}\Reg \\
-\Block &::= & \Instr\ldots \\
-\Def &::= & \LP\key{define} \; \LP\itm{label}\RP \;\LP\LP\itm{label} \,\key{.}\, \Block\RP\ldots\RP\RP\\
+\Block &::= & \Instr^{*} \\
+\Blocks &::=& \LP\LP\itm{label} \,\key{.}\, \Block\RP\ldots\RP\\
+\Def &::= & \LP\key{define} \; \LP\itm{label} \RP \; \Blocks \RP\\
 \LangXIndCallM{} &::= & \Def\ldots
 \LangXIndCallM{} &::= & \Def\ldots
 \end{array}
 \end{array}
 \]
 \]
@@ -14639,7 +14647,7 @@ a type annotation for the variable on the left-hand side.}
   \gray{\LfunGrammarPython} \\ \hline
   \gray{\LfunGrammarPython} \\ \hline
   \LlambdaGrammarPython \\
   \LlambdaGrammarPython \\
   \begin{array}{rcl}
   \begin{array}{rcl}
-    \LangFunM{} &::=& \Def^{*} \Stmt^{*}
+    \LangFunM{} &::=& \Def\ldots \Stmt\ldots
   \end{array}
   \end{array}
 \end{array}
 \end{array}
 \]
 \]
@@ -14794,7 +14802,7 @@ this book is compilation, not type inference.
 
 
 The main idea of bidirectional type inference is to add an auxilliary
 The main idea of bidirectional type inference is to add an auxilliary
 function, here named \code{check\_exp}, that takes an expected type
 function, here named \code{check\_exp}, that takes an expected type
-and checks whether the given expression can be of that type.  Thus, in
+and checks whether the given expression is of that type.  Thus, in
 \code{check\_exp}, type information flows in a top-down manner with
 \code{check\_exp}, type information flows in a top-down manner with
 respect to the AST, in contrast to the regular \code{type\_check\_exp}
 respect to the AST, in contrast to the regular \code{type\_check\_exp}
 function, where type information flows in a primarily bottom-up
 function, where type information flows in a primarily bottom-up
@@ -14816,9 +14824,9 @@ a program to sidestep the restriction, for example, by using an
 annotated assignment statement to assign the \code{lambda} to a
 annotated assignment statement to assign the \code{lambda} to a
 temporary variable.
 temporary variable.
 
 
-Note that for the \code{Name} and \code{Lambda} AST nodes, we record
-their type in a \code{has\_type} field. This type information is used
-later in this chapter.
+Note that for the \code{Name} and \code{Lambda} AST nodes, the type
+checker records their type in a \code{has\_type} field. This type
+information is used later in this chapter.
 %
 %
 \fi}
 \fi}
 
 
@@ -14965,15 +14973,17 @@ function \code{f} has a free variable \code{x} that is changed after
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
 {\if\edition\pythonEd
 {\if\edition\pythonEd
-%  assign_free.py
+%  box_free_assign.py
 \begin{lstlisting}
 \begin{lstlisting}
+def g(z : int) -> int:
     x = 0
     x = 0
     y = 0  
     y = 0  
-    z = 20
     f : Callable[[int],int] = lambda a: a + x + z
     f : Callable[[int],int] = lambda a: a + x + z
     x = 10
     x = 10
     y = 12
     y = 12
-    print( f(y) )
+    return f(y)
+
+print( g(20) )
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
 The correct output for this example is \code{42} because the call to
 The correct output for this example is \code{42} because the call to
@@ -15046,22 +15056,34 @@ the variable needs to live on the heap.  The verb
 value on the heap, producing a pointer, and
 value on the heap, producing a pointer, and
 \emph{unbox}\index{subject}{unbox} for dereferencing the pointer.
 \emph{unbox}\index{subject}{unbox} for dereferencing the pointer.
 
 
-{\if\edition\racketEd
-We recommend solving these problems by boxing the local variables that
-are in the intersection of 1) variables that appear on the
-left-hand-side of a \code{set!}  and 2) variables that occur free
-inside a \code{lambda}.
-\fi}
-{\if\edition\pythonEd
-We recommend solving these problems by boxing the local variables that
-are in the intersection of 1) variables whose values may change and 2)
-variables that occur free inside a \code{lambda}.
-\fi}
+%% {\if\edition\racketEd
+%% We recommend solving these problems by boxing the local variables that
+%% are in the intersection of 1) variables that appear on the
+%% left-hand-side of a \code{set!}  and 2) variables that occur free
+%% inside a \code{lambda}.
+%% \fi}
+%% {\if\edition\pythonEd
+%% We recommend solving these problems by boxing the local variables that
+%% are in the intersection of 1) variables whose values may change and 2)
+%% variables that occur free inside a \code{lambda}.
+%% \fi}
 We shall introduce a new pass named
 We shall introduce a new pass named
 \code{convert\_assignments} in Section~\ref{sec:convert-assignments}
 \code{convert\_assignments} in Section~\ref{sec:convert-assignments}
-to perform this translation. But before diving into the compiler
-passes, we one more problem to discuss.
+to address this challenge.
+%
+\racket{But before diving into the compiler passes, we have one more
+  problem to discuss.}
+
+\if\edition\pythonEd
+\section{Uniquify Variables}
+\label{sec:uniquify-lambda}
 
 
+UNDER CONSTRUCTION
+
+\fi
+
+
+\if\edition\racketEd
 \section{Reveal Functions and the $F_2$ language}
 \section{Reveal Functions and the $F_2$ language}
 \label{sec:reveal-functions-r5}
 \label{sec:reveal-functions-r5}
 
 
@@ -15090,23 +15112,29 @@ Figure~\ref{fig:f2-syntax}.
 \label{fig:f2-syntax}
 \label{fig:f2-syntax}
 \end{figure}
 \end{figure}
 
 
+\fi
 
 
-\section{Convert Assignments}
+\section{Assignment Conversion}
 \label{sec:convert-assignments}
 \label{sec:convert-assignments}
 
 
-[UNDER CONSTRUCTION: This section was just moved into this location
-and may need to be updated. -Jeremy]
-
-Recall that in Section~\ref{sec:assignment-scoping} we learned that
-the combination of assignments and lexically-scoped functions requires
-that we box those variables that are both assigned-to and that appear
-free inside a \code{lambda}. The purpose of the
-\code{convert-assignments} pass is to carry out that transformation.
-We recommend placing this pass after \code{uniquify} but before
-\code{reveal\_functions}.
+The purpose of the \code{convert\_assignments} pass is address the
+challenge posed in Section~\ref{sec:assignment-scoping} regarding the
+interaction between variable assignments and closure conversion.
+First we identify which variables need to be boxed, then we transform
+the program to box those variables. In general, boxing introduces
+runtime overhead that we would like to avoid, so we should box as few
+variables as possible. We recommend boxing the variables in the
+intersection of the following two sets of variables:
+\begin{enumerate}
+\item The variables that are free in a \code{lambda}.
+\item The variables that appear on the left-hand side of an
+  assignment.
+\end{enumerate}
 
 
 Consider again the first example from
 Consider again the first example from
 Section~\ref{sec:assignment-scoping}:
 Section~\ref{sec:assignment-scoping}:
+%
+{\if\edition\racketEd
 \begin{lstlisting}
 \begin{lstlisting}
 (let ([x 0])
 (let ([x 0])
   (let ([y 0])
   (let ([y 0])
@@ -15117,14 +15145,31 @@ Section~\ref{sec:assignment-scoping}:
           (set! y 12)
           (set! y 12)
           (f y))))))
           (f y))))))
 \end{lstlisting}
 \end{lstlisting}
-The variables \code{x} and \code{y} are assigned-to.  The variables
-\code{x} and \code{z} occur free inside the \code{lambda}. Thus,
-variable \code{x} needs to be boxed but not \code{y} and \code{z}.
-The boxing of \code{x} consists of three transformations: initialize
-\code{x} with a vector, replace reads from \code{x} with
-\code{vector-ref}'s, and replace each \code{set!} on \code{x} with a
-\code{vector-set!}. The output of \code{convert-assignments} for this
-example is as follows.
+\fi}
+{\if\edition\pythonEd
+\begin{lstlisting}
+def g(z : int) -> int:
+    x = 0
+    y = 0  
+    f : Callable[[int],int] = lambda a: a + x + z
+    x = 10
+    y = 12
+    return f(y)
+
+print( g(20) )
+\end{lstlisting}
+\fi}
+%
+\noindent The variables \code{x} and \code{y} are assigned-to.  The
+variables \code{x} and \code{z} occur free inside the
+\code{lambda}. Thus, variable \code{x} needs to be boxed but not
+\code{y} or \code{z}.  The boxing of \code{x} consists of three
+transformations: initialize \code{x} with a tuple, replace reads from
+\code{x} with tuple reads, and replace each assignment to \code{x}
+with a tuple writes. The output of \code{convert\_assignments} for
+this example is as follows.
+%
+{\if\edition\racketEd
 \begin{lstlisting}
 \begin{lstlisting}
 (define (main) : Integer
 (define (main) : Integer
   (let ([x0 (vector 0)])
   (let ([x0 (vector 0)])
@@ -15137,127 +15182,176 @@ example is as follows.
             (set! y1 12)
             (set! y1 12)
             (f4 y1)))))))
             (f4 y1)))))))
 \end{lstlisting}
 \end{lstlisting}
+\fi}
+%
+{\if\edition\pythonEd
+\begin{lstlisting}
+def g(z : int)-> int:
+  x = (0,)
+  x[0] = 0
+  y = 0
+  f : Callable[[int], int] = (lambda a: a + x[0] + z)
+  x[0] = 10
+  y = 12
+  return f(y)
+
+def main() -> int:
+  print(g(20))
+  return 0
+\end{lstlisting}
+\fi}
 
 
-\paragraph{Assigned \& Free}
+To compute the free variables of all the \code{lambda} expressions, we
+recommend defining two auxiliary functions:
+\begin{enumerate}
+\item \code{free\_variables} computes the free variables of an expression, and
+\item \code{free\_in\_lambda} collects all of the variables that are
+  free in any of the \code{lambda} expressions, using
+  \code{free\_variables} in the case for each \code{lambda}.
+\end{enumerate}
 
 
-We recommend defining an auxiliary function named
-\code{assigned\&free} that takes an expression and simultaneously
-computes 1) a set of assigned variables $A$, 2) a set $F$ of variables
-that occur free within lambda's, and 3) a new version of the
-expression that records which bound variables occurred in the
-intersection of $A$ and $F$. You can use the struct
-\code{AssignedFree} to do this. Consider the case for
-$\LET{x}{\itm{rhs}}{\itm{body}}$.  Suppose the the recursive call on
-$\itm{rhs}$ produces $\itm{rhs}'$, $A_r$, and $F_r$ and the recursive
-call on the $\itm{body}$ produces $\itm{body}'$, $A_b$, and $F_b$. If
-$x$ is in $A_b\cap F_b$, then transforms the \code{Let} as follows.
-\begin{lstlisting}
-  (Let |$x$| |$rhs$| |$body$|)
-  |$\Rightarrow$|
-  (Let (AssignedFree |$x$|) |$rhs'$| |$body'$|)
-\end{lstlisting}
-If $x$ is not in $A_b\cap F_b$ then omit the use of \code{AssignedFree}.
-The set of assigned variables for this \code{Let} is
-$A_r \cup (A_b - \{x\})$
-and the set of variables free in lambda's is
-$F_r \cup (F_b - \{x\})$.
-
-The case for $\SETBANG{x}{\itm{rhs}}$ is straightforward but
-important. Recursively process \itm{rhs} to obtain \itm{rhs'}, $A_r$,
-and $F_r$. The result is $\SETBANG{x}{\itm{rhs'}}$, $\{x\} \cup A_r$,
-and $F_r$.
-
-The case for $\LAMBDA{\itm{params}}{T}{\itm{body}}$ is a bit more
-involved.  Let \itm{body'}, $A_b$, and $F_b$ be the result of
-recursively processing \itm{body}. Wrap each of parameter that occurs
-in $A_b \cap F_b$ with \code{AssignedFree} to produce \itm{params'}.
-Let $P$ be the set of parameter names in \itm{params}.  The result is
-$\LAMBDA{\itm{params'}}{T}{\itm{body'}}$, $A_b - P$, and $(F_b \cup
-\mathrm{FV}(\itm{body})) - P$, where $\mathrm{FV}$ computes the free
-variables of an expression (see Chapter~\ref{ch:Rlam}).
-
-\paragraph{Convert Assignments}
-
-Next we discuss the \code{convert-assignment} pass with its auxiliary
-functions for expressions and definitions. The function for
-expressions, \code{cnvt-assign-exp}, should take an expression and a
-set of assigned-and-free variables (obtained from the result of
-\code{assigned\&free}. In the case for $\VAR{x}$, if $x$ is
-assigned-and-free, then unbox it by translating $\VAR{x}$ to a
-\code{vector-ref}.
+
+{\if\edition\racketEd
+%
+To compute the variables that are assigned-to, we recommend using the
+\code{collect-set!} function that we introduced in
+Section~\ref{sec:uncover-get-bang}, but updated to include the new AST
+forms such as \code{Lambda}.
+%
+\fi}
+  
+{\if\edition\pythonEd
+%
+To compute the variables that are assigned-to, we recommend defining
+an auxiliary function named \code{assigned\_vars\_stmt} that returns
+the set of variables that occur in the left-hand side of an assignment
+statement, and otherwise returns the empty set.
+%
+\fi}
+
+Let $\mathit{AF}$ be the intersection of the set of variables that are
+free in a \code{lambda} and that are assigned-to in the enclosing
+function definition.
+
+Next we discuss the \code{convert\_assignments} pass.  In the case for
+$\VAR{x}$, if $x$ is in $\mathit{AF}$, then unbox it by translating
+$\VAR{x}$ to a tuple read.
+%
+{\if\edition\racketEd
 \begin{lstlisting}
 \begin{lstlisting}
   (Var |$x$|)
   (Var |$x$|)
   |$\Rightarrow$|
   |$\Rightarrow$|
   (Prim 'vector-ref (list (Var |$x$|) (Int 0)))
   (Prim 'vector-ref (list (Var |$x$|) (Int 0)))
 \end{lstlisting}
 \end{lstlisting}
+\fi}
 %
 %
-In the case for $\LET{\LP\code{AssignedFree}\,
-  x\RP}{\itm{rhs}}{\itm{body}}$, recursively process \itm{rhs} to
-obtain \itm{rhs'}.  Next, recursively process \itm{body} to obtain
-\itm{body'} but with $x$ added to the set of assigned-and-free
-variables.  Translate the let-expression as follows to bind $x$ to a
-boxed value.
+{\if\edition\pythonEd
 \begin{lstlisting}
 \begin{lstlisting}
-  (Let (AssignedFree |$x$|) |$rhs$| |$body$|)
+  Name(|$x$|)
   |$\Rightarrow$|
   |$\Rightarrow$|
-  (Let |$x$| (Prim 'vector (list |$rhs'$|)) |$body'$|)
+  Subscript(Name(|$x$|), Constant(0), Load())
 \end{lstlisting}
 \end{lstlisting}
+\fi}
 %
 %
-In the case for $\SETBANG{x}{\itm{rhs}}$, recursively process
-\itm{rhs} to obtain \itm{rhs'}.  If $x$ is in the assigned-and-free
-variables, translate the \code{set!} into a \code{vector-set!}
-as follows.
+%
+In the case for assignment, recursively process the right-hand side
+\itm{rhs} to obtain \itm{rhs'}.  If $x$ is in $\mathit{AF}$, translate
+the assignment into a tuple-write as follows.
+%
+{\if\edition\racketEd
 \begin{lstlisting}
 \begin{lstlisting}
   (SetBang |$x$| |$\itm{rhs}$|)
   (SetBang |$x$| |$\itm{rhs}$|)
   |$\Rightarrow$|
   |$\Rightarrow$|
   (Prim 'vector-set! (list (Var |$x$|) (Int 0) |$\itm{rhs'}$|))
   (Prim 'vector-set! (list (Var |$x$|) (Int 0) |$\itm{rhs'}$|))
 \end{lstlisting}
 \end{lstlisting}
+\fi}
+{\if\edition\pythonEd
+\begin{lstlisting}
+  Assign([Name(|$x$|)],|$\itm{rhs}$|)
+  |$\Rightarrow$|
+  Assign([Subscript(Name(|$x$|), Constant(0), Store())], |$\itm{rhs'}$|)
+\end{lstlisting}
+\fi}
 %
 %
+{\if\edition\racketEd
 The case for \code{Lambda} is non-trivial, but it is similar to the
 The case for \code{Lambda} is non-trivial, but it is similar to the
 case for function definitions, which we discuss next.
 case for function definitions, which we discuss next.
+\fi}
 
 
-The auxiliary function for definitions, \code{cnvt-assign-def},
-applies assignment conversion to function definitions.
-We translate a function definition as follows.
+To translate a function definition, we first compute $\mathit{AF}$,
+the intersection of the variables that are free in a \code{lambda} and
+that are assigned-to. We then apply assignment conversion to the body
+of the function definition. Finally, we box the parameters of this
+function definition that are in $\mathit{AF}$. For example,
+the parameter \code{x} of the follow function \code{g}
+needs to be boxed.
+{\if\edition\racketEd
 \begin{lstlisting}
 \begin{lstlisting}
-  (Def |$f$| |$\itm{params}$| |$T$| |$\itm{info}$| |$\itm{body_1}$|)
-  |$\Rightarrow$|
-  (Def |$f$| |$\itm{params'}$| |$T$| |$\itm{info}$| |$\itm{body_4}$|)
-\end{lstlisting}
-So it remains to explain \itm{params'} and $\itm{body}_4$.
-Let \itm{body_2}, $A_b$, and $F_b$ be the result of
-\code{assigned\&free} on $\itm{body_1}$.
-Let $P$ be the parameter names in \itm{params}.
-We then apply \code{cnvt-assign-exp} to $\itm{body_2}$ to
-obtain \itm{body_3}, passing $A_b \cap F_b \cap P$
-as the set of assigned-and-free variables.
-Finally, we obtain \itm{body_4} by wrapping \itm{body_3}
-in a sequence of let-expressions that box the parameters
-that are in $A_b \cap F_b$.
-%
-Regarding \itm{params'}, change the names of the parameters that are
-in $A_b \cap F_b$ to maintain uniqueness (and so the let-bound
-variables can retain the original names). Recall the second example in
-Section~\ref{sec:assignment-scoping} involving a counter
-abstraction. The following is the output of assignment version for
-function \code{f}.
-\begin{lstlisting}
-(define (f0 [x1 : Integer]) : (Vector ( -> Integer) ( -> Void))
-  (vector
-   (lambda: () : Integer x1)
-   (lambda: () : Void (set! x1 (+ 1 x1)))))
-|$\Rightarrow$|
-(define (f0 [param_x1 : Integer]) : (Vector (-> Integer) (-> Void))
-  (let ([x1 (vector param_x1)])
-    (vector (lambda: () : Integer (vector-ref x1 0))
-             (lambda: () : Void
-                (vector-set! x1 0 (+ 1 (vector-ref x1 0)))))))
+(define (g [x : Integer]) : Integer
+  (let ([f (lambda: ([a : Integer]) : Integer (+ a x))])
+    (begin
+      (set! x 10)
+      (f 32))))
+\end{lstlisting}
+\fi}
+%
+{\if\edition\pythonEd
+\begin{lstlisting}
+def g(x : int) -> int:
+  f : Callable[[int],int] = lambda a: a + x
+  x = 10
+  return f(32)
+\end{lstlisting}
+\fi}
+%
+\noindent We box parameter \code{x} by creating a local variable named
+\code{x} that is initialized to a tuple whose contents is the value of
+the parameter, which we has been renamed.
+%
+{\if\edition\racketEd
+\begin{lstlisting}
+(define (g [x_0 : Integer]) : Integer
+  (let ([x (vector x_0)])
+    (let ([f (lambda: ([a : Integer]) : Integer
+               (+ a (vector-ref x 0)))])
+      (begin 
+        (vector-set! x 0 10)
+        (f 32)))))
+\end{lstlisting}
+\fi}
+%
+{\if\edition\pythonEd
+\begin{lstlisting}
+def g(x_0 : int)-> int:
+  x = (x_0,)
+  f : Callable[[int], int] = (lambda a: a + x[0])
+  x[0] = 10
+  return f(32)
 \end{lstlisting}
 \end{lstlisting}
+\fi}
+
+%% Recall the second example in Section~\ref{sec:assignment-scoping}
+%% involving a counter abstraction. The following is the output of
+%% assignment version for function \code{f}.
+%% \begin{lstlisting}
+%% (define (f0 [x1 : Integer]) : (Vector ( -> Integer) ( -> Void))
+%%   (vector
+%%    (lambda: () : Integer x1)
+%%    (lambda: () : Void (set! x1 (+ 1 x1)))))
+%% |$\Rightarrow$|
+%% (define (f0 [param_x1 : Integer]) : (Vector (-> Integer) (-> Void))
+%%   (let ([x1 (vector param_x1)])
+%%     (vector (lambda: () : Integer (vector-ref x1 0))
+%%              (lambda: () : Void
+%%                 (vector-set! x1 0 (+ 1 (vector-ref x1 0)))))))
+%% \end{lstlisting}
 
 
 \section{Closure Conversion}
 \section{Closure Conversion}
 \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

+ 3 - 1
defs.tex

@@ -99,6 +99,8 @@
 \newcommand{\FType}{\itm{ftype}}
 \newcommand{\FType}{\itm{ftype}}
 \newcommand{\Instr}{\itm{instr}}
 \newcommand{\Instr}{\itm{instr}}
 \newcommand{\Block}{\itm{block}}
 \newcommand{\Block}{\itm{block}}
+\newcommand{\Blocks}{\itm{blocks}}
+\newcommand{\Params}{\itm{params}}
 \newcommand{\Tail}{\itm{tail}}
 \newcommand{\Tail}{\itm{tail}}
 \newcommand{\Prog}{\itm{prog}}
 \newcommand{\Prog}{\itm{prog}}
 \newcommand{\Arg}{\itm{arg}}
 \newcommand{\Arg}{\itm{arg}}
@@ -282,7 +284,7 @@
 \if\edition\pythonEd
 \if\edition\pythonEd
 \newcommand{\LAMBDA}[2]{\key{Lambda}\LP#1\code{, }#2\RP}
 \newcommand{\LAMBDA}[2]{\key{Lambda}\LP#1\code{, }#2\RP}
 \newcommand{\CLAMBDA}[2]{\key{lambda}\,#1\,\key{:}\,#2}
 \newcommand{\CLAMBDA}[2]{\key{lambda}\,#1\,\key{:}\,#2}
-\newcommand{\TAILCALL}[2]{\key{TailCall}\LP#1\code{,}#2\RP}
+\newcommand{\TAILCALL}[2]{\key{TailCall}\LP#1\code{, }#2\RP}
 \newcommand{\CASSIGN}[2]{#1~\key{=}~#2}
 \newcommand{\CASSIGN}[2]{#1~\key{=}~#2}
 \newcommand{\ASSIGN}[2]{\key{Assign}\LP\LS #1\RS\key{, }#2\RP}
 \newcommand{\ASSIGN}[2]{\key{Assign}\LP\LS #1\RS\key{, }#2\RP}
 \newcommand{\CANNASSIGN}[3]{#1~\key{:}~#2~\key{=}~#3}
 \newcommand{\CANNASSIGN}[3]{#1~\key{:}~#2~\key{=}~#3}