Jeremy Siek 3 жил өмнө
parent
commit
fe049c6bf3
1 өөрчлөгдсөн 77 нэмэгдсэн , 101 устгасан
  1. 77 101
      book.tex

+ 77 - 101
book.tex

@@ -14797,21 +14797,22 @@ that a function's body may refer to variables whose binding site is
 outside of the function, in an enclosing scope.
 outside of the function, in an enclosing scope.
 %
 %
 Consider the example in Figure~\ref{fig:lexical-scoping} written in
 Consider the example in Figure~\ref{fig:lexical-scoping} written in
-\LangLam{}, which extends \LangFun{} with lexically scoped functions
-using the \key{lambda} form.  The body of the \key{lambda} refers to
-three variables: \code{x}, \code{y}, and \code{z}. The binding sites
-for \code{x} and \code{y} are outside of the \key{lambda}. Variable
-\code{y} is \racket{bound by the enclosing \key{let}}\python{a local
-  variable of function \code{f}} and \code{x} is a parameter of
-function \code{f}. The \key{lambda} is returned from the function
-\code{f}. The main expression of the program includes two calls to
-\code{f} with different arguments for \code{x}, first \code{5} then
-\code{3}. The functions returned from \code{f} are bound to variables
-\code{g} and \code{h}. Even though these two functions were created by
-the same \code{lambda}, they are really different functions because
-they use different values for \code{x}. Applying \code{g} to \code{11}
-produces \code{20} whereas applying \code{h} to \code{15} produces
-\code{22}. The result of this program is \code{42}.
+\LangLam{}, which extends \LangFun{} with the \key{lambda} form for
+creating lexically scoped functions.  The body of the \key{lambda}
+refers to three variables: \code{x}, \code{y}, and \code{z}. The
+binding sites for \code{x} and \code{y} are outside of the
+\key{lambda}. Variable \code{y} is \racket{bound by the enclosing
+  \key{let}}\python{a local variable of function \code{f}} and
+\code{x} is a parameter of function \code{f}. Note that function
+\code{f} returns the \key{lambda} as its result value. The main
+expression of the program includes two calls to \code{f} with
+different arguments for \code{x}, first \code{5} then \code{3}. The
+functions returned from \code{f} are bound to variables \code{g} and
+\code{h}. Even though these two functions were created by the same
+\code{lambda}, they are really different functions because they use
+different values for \code{x}. Applying \code{g} to \code{11} produces
+\code{20} whereas applying \code{h} to \code{15} produces \code{22},
+so the result of the program is \code{42}.
 
 
 \begin{figure}[btp]
 \begin{figure}[btp]
 {\if\edition\racketEd
 {\if\edition\racketEd
@@ -14883,22 +14884,22 @@ of the free variables together with a function pointer into a tuple,
 an arrangement called a \emph{flat closure} (which we shorten to just
 an arrangement called a \emph{flat closure} (which we shorten to just
 ``closure'').\index{subject}{closure}\index{subject}{flat closure}
 ``closure'').\index{subject}{closure}\index{subject}{flat closure}
 %
 %
-Fortunately, we have all the ingredients to make closures:
+By design, we have all the ingredients to make closures:
 Chapter~\ref{ch:Lvec} gave us tuples and Chapter~\ref{ch:Lfun} gave us
 Chapter~\ref{ch:Lvec} gave us tuples and Chapter~\ref{ch:Lfun} gave us
 function pointers. The function pointer resides at index $0$ and the
 function pointers. The function pointer resides at index $0$ and the
 values for the free variables fill in the rest of the tuple.
 values for the free variables fill in the rest of the tuple.
 
 
 Let us revisit the example in Figure~\ref{fig:lexical-scoping} to see
 Let us revisit the example in Figure~\ref{fig:lexical-scoping} to see
-how closures work. It's a three-step dance. The program calls function
-\code{f}, which creates a closure for the \code{lambda}. The closure
-is a tuple whose first element is a pointer to the top-level function
-that we will generate for the \code{lambda}, the second element is the
-value of \code{x}, which is \code{5}, and the third element is
-\code{4}, the value of \code{y}. The closure does not contain an
-element for \code{z} because \code{z} is not a free variable of the
-\code{lambda}. Creating the closure is step 1 of the dance. The
-closure is returned from \code{f} and bound to \code{g}, as shown in
-Figure~\ref{fig:closures}.
+how closures work. It is a three-step dance. The program calls
+function \code{f}, which creates a closure for the \code{lambda}. The
+closure is a tuple whose first element is a pointer to the top-level
+function that we will generate for the \code{lambda}, the second
+element is the value of \code{x}, which is \code{5}, and the third
+element is \code{4}, the value of \code{y}. The closure does not
+contain an element for \code{z} because \code{z} is not a free
+variable of the \code{lambda}. Creating the closure is step 1 of the
+dance. The closure is returned from \code{f} and bound to \code{g}, as
+shown in Figure~\ref{fig:closures}.
 %
 %
 The second call to \code{f} creates another closure, this time with
 The second call to \code{f} creates another closure, this time with
 \code{3} in the second slot (for \code{x}). This closure is also
 \code{3} in the second slot (for \code{x}). This closure is also
@@ -14914,7 +14915,7 @@ Figure~\ref{fig:closures}.
 
 
 Continuing with the example, consider the application of \code{g} to
 Continuing with the example, consider the application of \code{g} to
 \code{11} in Figure~\ref{fig:lexical-scoping}.  To apply a closure, we
 \code{11} in Figure~\ref{fig:lexical-scoping}.  To apply a closure, we
-obtain the function pointer in the first element of the closure and
+obtain the function pointer from the first element of the closure and
 call it, passing in the closure itself and then the regular arguments,
 call it, passing in the closure itself and then the regular arguments,
 in this case \code{11}. This technique for applying a closure is step
 in this case \code{11}. This technique for applying a closure is step
 2 of the dance.
 2 of the dance.
@@ -14928,9 +14929,9 @@ appropriate elements from the closure parameter.
 %
 %
 This three-step dance is known as \emph{closure conversion}.  We
 This three-step dance is known as \emph{closure conversion}.  We
 discuss the details of closure conversion in
 discuss the details of closure conversion in
-Section~\ref{sec:closure-conversion} and the code generated from the
-example in Section~\ref{sec:example-lambda}. But first we define the
-syntax and semantics of \LangLam{} in Section~\ref{sec:r5}.
+Section~\ref{sec:closure-conversion} and show the code generated from
+the example in Section~\ref{sec:example-lambda}. But first we define
+the syntax and semantics of \LangLam{} in Section~\ref{sec:r5}.
 
 
 \section{The \LangLam{} Language}
 \section{The \LangLam{} Language}
 \label{sec:r5}
 \label{sec:r5}
@@ -14946,6 +14947,10 @@ syntax for function application.
   facilitates the type checking of \code{lambda} expressions that we
   facilitates the type checking of \code{lambda} expressions that we
   discuss later in this section.}
   discuss later in this section.}
 %
 %
+\racket{The \code{procedure-arity} operation returns the number of parameters
+  of a given function, an operation that we need for the translation
+  of dynamic typing in Chapter~\ref{ch:Ldyn}.}
+%
 \python{The \code{arity} operation returns the number of parameters of
 \python{The \code{arity} operation returns the number of parameters of
   a given function, an operation that we need for the translation
   a given function, an operation that we need for the translation
   of dynamic typing in Chapter~\ref{ch:Ldyn}.
   of dynamic typing in Chapter~\ref{ch:Ldyn}.
@@ -14955,14 +14960,14 @@ syntax for function application.
 
 
 \newcommand{\LlambdaGrammarRacket}{
 \newcommand{\LlambdaGrammarRacket}{
   \begin{array}{lcl}
   \begin{array}{lcl}
-  \Exp &::=& \LP \key{procedure-arity}~\Exp\RP \\
-    &\MID& \CLAMBDA{\LP\LS\Var \key{:} \Type\RS\ldots\RP}{\Type}{\Exp} 
+  \Exp &::=&  \CLAMBDA{\LP\LS\Var \key{:} \Type\RS\ldots\RP}{\Type}{\Exp} \\
+    &\MID& \LP \key{procedure-arity}~\Exp\RP
   \end{array}
   \end{array}
 }
 }
 \newcommand{\LlambdaASTRacket}{
 \newcommand{\LlambdaASTRacket}{
   \begin{array}{lcl}
   \begin{array}{lcl}
-  \itm{op} &::=& \code{procedure-arity} \\
-  \Exp &::=& \LAMBDA{\LP\LS\Var\code{:}\Type\RS\ldots\RP}{\Type}{\Exp}
+  \Exp &::=& \LAMBDA{\LP\LS\Var\code{:}\Type\RS\ldots\RP}{\Type}{\Exp}\\
+  \itm{op} &::=& \code{procedure-arity} 
   \end{array}
   \end{array}
 }
 }
 
 
@@ -15071,9 +15076,9 @@ syntax for function application.
 \end{figure}
 \end{figure}
 
 
 \index{subject}{interpreter}
 \index{subject}{interpreter}
-\label{sec:interp-Rlambda}
+\label{sec:interp-Llambda}
 
 
-Figure~\ref{fig:interp-Rlambda} shows the definitional interpreter for
+Figure~\ref{fig:interp-Llambda} shows the definitional interpreter for
 \LangLam{}. The case for \key{Lambda} saves the current environment
 \LangLam{}. The case for \key{Lambda} saves the current environment
 inside the returned function value. Recall that during function
 inside the returned function value. Recall that during function
 application, the environment stored in the function value, extended
 application, the environment stored in the function value, extended
@@ -15104,7 +15109,7 @@ interpret the body of the function.
         [else ((super interp-exp env) e)]))
         [else ((super interp-exp env) e)]))
     ))
     ))
 
 
-(define (interp-Rlambda p)
+(define (interp-Llambda p)
   (send (new interp-Llambda-class) interp-program p))
   (send (new interp-Llambda-class) interp-program p))
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
@@ -15141,7 +15146,7 @@ class InterpLlambda(InterpLfun):
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
 \caption{Interpreter for \LangLam{}.}
 \caption{Interpreter for \LangLam{}.}
-\label{fig:interp-Rlambda}
+\label{fig:interp-Llambda}
 \end{figure}
 \end{figure}
 
 
 
 
@@ -15204,7 +15209,7 @@ information is used later in this chapter.
 \begin{figure}[tbp]
 \begin{figure}[tbp]
 {\if\edition\racketEd 
 {\if\edition\racketEd 
 \begin{lstlisting}
 \begin{lstlisting}
-(define (type-check-Rlambda env)
+(define (type-check-Llambda env)
   (lambda (e)
   (lambda (e)
     (match e
     (match e
       [(Lambda (and params `([,xs : ,Ts] ...)) rT body)
       [(Lambda (and params `([,xs : ,Ts] ...)) rT body)
@@ -15331,10 +15336,10 @@ class TypeCheckLlambda(TypeCheckLfun):
 \label{sec:assignment-scoping}
 \label{sec:assignment-scoping}
 
 
 The combination of lexically-scoped functions and assignment to
 The combination of lexically-scoped functions and assignment to
-variables raises a challenge with our approach to implementing
-lexically-scoped functions. Consider the following example in which
-function \code{f} has a free variable \code{x} that is changed after
-\code{f} is created but before the call to \code{f}.
+variables raises a challenge with the flat-closure approach to
+implementing lexically-scoped functions. Consider the following
+example in which function \code{f} has a free variable \code{x} that
+is changed after \code{f} is created but before the call to \code{f}.
 % loop_test_11.rkt
 % loop_test_11.rkt
 {\if\edition\racketEd
 {\if\edition\racketEd
 \begin{lstlisting}
 \begin{lstlisting}
@@ -15361,42 +15366,24 @@ def g(z : int) -> int:
 
 
 print( g(20) )
 print( g(20) )
 \end{lstlisting}
 \end{lstlisting}
-\fi}
-The correct output for this example is \code{42} because the call to
-\code{f} is required to use the current value of \code{x} (which is
+\fi} The correct output for this example is \code{42} because the call
+to \code{f} is required to use the current value of \code{x} (which is
 \code{10}). Unfortunately, the closure conversion pass
 \code{10}). Unfortunately, the closure conversion pass
 (Section~\ref{sec:closure-conversion}) generates code for the
 (Section~\ref{sec:closure-conversion}) generates code for the
 \code{lambda} that copies the old value of \code{x} into a
 \code{lambda} that copies the old value of \code{x} into a
-closure. Thus, if we naively add support for assignment to our current
-compiler, the output of this program would be \code{32}.
+closure. Thus, if we naively apply closure conversion, the output of
+this program would be \code{32}.
 
 
 A first attempt at solving this problem would be to save a pointer to
 A first attempt at solving this problem would be to save a pointer to
 \code{x} in the closure and change the occurrences of \code{x} inside
 \code{x} in the closure and change the occurrences of \code{x} inside
 the lambda to dereference the pointer. Of course, this would require
 the lambda to dereference the pointer. Of course, this would require
 assigning \code{x} to the stack and not to a register. However, the
 assigning \code{x} to the stack and not to a register. However, the
 problem goes a bit deeper.
 problem goes a bit deeper.
-%% Consider the following example in which we
-%% create a counter abstraction by creating a pair of functions that
-%% share the free variable \code{x}.
 Consider the following example that returns a function that refers to
 Consider the following example that returns a function that refers to
 a local variable of the enclosing function.
 a local variable of the enclosing function.
 \begin{center}
 \begin{center}
 \begin{minipage}{\textwidth}
 \begin{minipage}{\textwidth}
 {\if\edition\racketEd
 {\if\edition\racketEd
-% similar to loop_test_10.rkt
-%% \begin{lstlisting}
-%% (define (f [x : Integer]) : (Vector ( -> Integer) ( -> Void))
-%%   (vector
-%%    (lambda: () : Integer x)
-%%    (lambda: () : Void (set! x (+ 1 x)))))
-
-%% (let ([counter (f 0)])
-%%   (let ([get (vector-ref counter 0)])
-%%     (let ([inc (vector-ref counter 1)])
-%%       (begin
-%%         (inc)
-%%         (get)))))
-%% \end{lstlisting}
 \begin{lstlisting}
 \begin{lstlisting}
 (define (f []) : Integer
 (define (f []) : Integer
   (let ([x 0])
   (let ([x 0])
@@ -15431,23 +15418,11 @@ the variable needs to live on the heap.  The verb
 \emph{box}\index{subject}{box} is often used for allocating a single
 \emph{box}\index{subject}{box} is often used for allocating a single
 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}
-We shall introduce a new pass named
-\code{convert\_assignments} in Section~\ref{sec:convert-assignments}
-to address this challenge.
 %
 %
-\racket{But before diving into the compiler passes, we have one more
+We introduce a new pass named \code{convert\_assignments} to address
+this challenge.
+%
+\python{But before diving into that, we have one more
   problem to discuss.}
   problem to discuss.}
 
 
 \if\edition\pythonEd
 \if\edition\pythonEd
@@ -15520,20 +15495,21 @@ def main() -> int :
 \label{sec:convert-assignments}
 \label{sec:convert-assignments}
 
 
 The purpose of the \code{convert\_assignments} pass is to address the
 The purpose of the \code{convert\_assignments} pass is to 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:
+challenge 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}
 \begin{enumerate}
 \item The variables that are free in a \code{lambda}.
 \item The variables that are free in a \code{lambda}.
 \item The variables that appear on the left-hand side of an
 \item The variables that appear on the left-hand side of an
   assignment.
   assignment.
 \end{enumerate}
 \end{enumerate}
-The first condition is a must, but the second condition is quite conservative and it is possible to
-develop a more liberal condition. 
+The first condition is a must but the second condition is
+conservative. It is possible to develop a more liberal condition using
+static program analysis.
 
 
 Consider again the first example from
 Consider again the first example from
 Section~\ref{sec:assignment-scoping}:
 Section~\ref{sec:assignment-scoping}:
@@ -15657,10 +15633,10 @@ $\VAR{x}$ to a tuple read.
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
 %
 %
-%
-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.
+\noindent In the case for assignment, recursively process the
+right-hand side \itm{rhs} to obtain \itm{rhs'}.  If the left-hand side
+$x$ is in $\mathit{AF}$, translate the assignment into a tuple-write
+as follows.
 %
 %
 {\if\edition\racketEd
 {\if\edition\racketEd
 \begin{lstlisting}
 \begin{lstlisting}
@@ -15681,7 +15657,7 @@ the assignment into a tuple-write as follows.
 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}
 \fi}
-
+%
 To translate a function definition, we first compute $\mathit{AF}$,
 To translate a function definition, we first compute $\mathit{AF}$,
 the intersection of the variables that are free in a \code{lambda} and
 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
 that are assigned-to. We then apply assignment conversion to the body
@@ -15710,7 +15686,7 @@ def g(x : int) -> int:
 %
 %
 \noindent We box parameter \code{x} by creating a local variable named
 \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
 \code{x} that is initialized to a tuple whose contents is the value of
-the parameter, which we has been renamed.
+the parameter, which has been renamed to \code{x\_0}.
 %
 %
 {\if\edition\racketEd
 {\if\edition\racketEd
 \begin{lstlisting}
 \begin{lstlisting}
@@ -16095,7 +16071,7 @@ abstract syntax is defined in Figure~\ref{fig:Clam-syntax}.
 
 
 
 
 \section{Select Instructions}
 \section{Select Instructions}
-\label{sec:select-instructions-Rlambda}
+\label{sec:select-instructions-Llambda}
 
 
 Compile \ALLOCCLOS{\itm{len}}{\itm{type}}{\itm{arity}} in almost the
 Compile \ALLOCCLOS{\itm{len}}{\itm{type}}{\itm{arity}} in almost the
 same way as the \ALLOC{\itm{len}}{\itm{type}} form
 same way as the \ALLOC{\itm{len}}{\itm{type}} form
@@ -16170,10 +16146,10 @@ $58$ from the tag.}
 \end{tikzpicture}
 \end{tikzpicture}
   \caption{Diagram of the passes for \LangLam{}, a language with lexically-scoped
   \caption{Diagram of the passes for \LangLam{}, a language with lexically-scoped
   functions.}
   functions.}
-\label{fig:Rlambda-passes}
+\label{fig:Llambda-passes}
 \end{figure}
 \end{figure}
 
 
-Figure~\ref{fig:Rlambda-passes} provides an overview of all the passes needed
+Figure~\ref{fig:Llambda-passes} provides an overview of all the passes needed
 for the compilation of \LangLam{}.
 for the compilation of \LangLam{}.
 
 
 \clearpage
 \clearpage
@@ -17092,7 +17068,7 @@ its auxiliary functions are in Figure~\ref{fig:interp-Lany-aux}.
 {\if\edition\racketEd
 {\if\edition\racketEd
 \begin{lstlisting}[basicstyle=\ttfamily\small]
 \begin{lstlisting}[basicstyle=\ttfamily\small]
 (define type-check-Rany-class
 (define type-check-Rany-class
-  (class type-check-Rlambda-class
+  (class type-check-Llambda-class
     (super-new)
     (super-new)
     (inherit check-type-equal?)
     (inherit check-type-equal?)
 
 
@@ -20516,7 +20492,7 @@ registers.
 % LocalWords:  InterpLfun FunRef TypeCheckLfun leaq callee's mainDef
 % LocalWords:  InterpLfun FunRef TypeCheckLfun leaq callee's mainDef
 % LocalWords:  ProgramDefs TailCall tailjmp IndirectCallq TailJmp rT
 % LocalWords:  ProgramDefs TailCall tailjmp IndirectCallq TailJmp rT
 % LocalWords:  prepending addstart addconclusion Cardelli Llambda typ
 % LocalWords:  prepending addstart addconclusion Cardelli Llambda typ
-% LocalWords:  Rlambda InterpLlambda AnnAssign Dunfield bodyT str fvs
+% LocalWords:  Llambda InterpLlambda AnnAssign Dunfield bodyT str fvs
 % LocalWords:  TypeCheckLlambda annot dereference clos fvts closTy
 % LocalWords:  TypeCheckLlambda annot dereference clos fvts closTy
 % LocalWords:  Minamide AllocateClosure Gilray Milner morphos subtype
 % LocalWords:  Minamide AllocateClosure Gilray Milner morphos subtype
 % LocalWords:  polymorphism untyped AnyType dataclass untag Rdyn
 % LocalWords:  polymorphism untyped AnyType dataclass untag Rdyn