فهرست منبع

more progress on closure conversion

Jeremy Siek 9 سال پیش
والد
کامیت
6d638a89a1
3فایلهای تغییر یافته به همراه124 افزوده شده و 7 حذف شده
  1. BIN
      Closures.graffle/data.plist
  2. 124 7
      book.tex
  3. BIN
      closures.pdf

BIN
Closures.graffle/data.plist


+ 124 - 7
book.tex

@@ -4385,6 +4385,7 @@ representation.)
 (assign |$\itm{lhs}$| (vector-set! |$\itm{vec}$| |$n$| |$\itm{arg}$|))
 (assign |$\itm{lhs}$| (vector-set! |$\itm{vec}$| |$n$| |$\itm{arg}$|))
 |$\Longrightarrow$|
 |$\Longrightarrow$|
 (movq |$\itm{arg}'$| (offset |$\itm{vec}'$| |$8(n+1)$|))
 (movq |$\itm{arg}'$| (offset |$\itm{vec}'$| |$8(n+1)$|))
+(mvoq (int 0) |$\itm{lhs}$|)
 \end{lstlisting}
 \end{lstlisting}
 The $\itm{vec}'$ and $\itm{arg}'$ are obtained by recursively
 The $\itm{vec}'$ and $\itm{arg}'$ are obtained by recursively
 processing $\itm{vec}$ and $\itm{arg}$.
 processing $\itm{vec}$ and $\itm{arg}$.
@@ -4964,7 +4965,7 @@ defined using the \key{lambda} form.
 \begin{lstlisting}
 \begin{lstlisting}
    (define (f [x : Integer]) : (Integer -> Integer)
    (define (f [x : Integer]) : (Integer -> Integer)
       (let ([y 4])
       (let ([y 4])
-         (lambda ([z : Integer]) : Integer
+         (lambda: ([z : Integer]) : Integer
             (+ x (+ y z)))))
             (+ x (+ y z)))))
 
 
    (let ([g (f 5)])
    (let ([g (f 5)])
@@ -4988,6 +4989,8 @@ they use different values for \code{x}. Finally, we apply \code{g} to
 \code{11} (producing \code{20}) and apply \code{h} to \code{15}
 \code{11} (producing \code{20}) and apply \code{h} to \code{15}
 (producing \code{22}) so the result of this program is \code{42}.
 (producing \code{22}) so the result of this program is \code{42}.
 
 
+\section{The $R_5$ Language}
+
 The syntax for this language with lexical scoping, $R_5$, is defined
 The syntax for this language with lexical scoping, $R_5$, is defined
 in Figure~\ref{fig:r5-syntax}. It adds the \key{lambda} form to the
 in Figure~\ref{fig:r5-syntax}. It adds the \key{lambda} form to the
 grammar for $R_4$, which already has syntax for function application.
 grammar for $R_4$, which already has syntax for function application.
@@ -5029,11 +5032,11 @@ free with respect to the expression \code{(+ x (+ y z))}.  On the
 other hand, only \code{x} and \code{y} are free with respect to the
 other hand, only \code{x} and \code{y} are free with respect to the
 following expression becuase \code{z} is bound by the \code{lambda}.
 following expression becuase \code{z} is bound by the \code{lambda}.
 \begin{lstlisting}
 \begin{lstlisting}
-   (lambda ([z : Integer]) : Integer
+   (lambda: ([z : Integer]) : Integer
       (+ x (+ y z)))
       (+ x (+ y z)))
 \end{lstlisting}
 \end{lstlisting}
 
 
-Once we have identified the free variables of a \code{lamda}, we need
+Once we have identified the free variables of a \code{lambda}, we need
 to arrange for some way to transport, at runtime, the values of those
 to arrange for some way to transport, at runtime, the values of those
 variables from the point where the \code{lambda} was created to the
 variables from the point where the \code{lambda} was created to the
 point where the \code{lambda} is applied. Referring again to
 point where the \code{lambda} is applied. Referring again to
@@ -5047,17 +5050,131 @@ already have the appropriate ingredients to make closures,
 Chapter~\ref{ch:tuples} gave us tuples and Chapter~\ref{ch:functions}
 Chapter~\ref{ch:tuples} gave us tuples and Chapter~\ref{ch:functions}
 gave us function pointers. The function pointer shall reside at index
 gave us function pointers. The function pointer shall reside at index
 $0$ and the values for free variables will fill in the rest of the
 $0$ and the values for free variables will fill in the rest of the
-tuple.
-
+tuple. Figure~\ref{fig:closures} depicts the two closures created by
+the two calls to \code{f} in Figure~\ref{fig:lexical-scoping}.
+Because the two closures came from the same \key{lambda}, they share
+the same code but differ in the values for free variable \code{x}.
 
 
 \begin{figure}[tbp]
 \begin{figure}[tbp]
-\centering \includegraphics[width=0.8\textwidth]{closures}
+\centering \includegraphics[width=0.7\textwidth]{closures}
 \caption{Example closure representation for the \key{lambda}'s
 \caption{Example closure representation for the \key{lambda}'s
   in Figure~\ref{fig:lexical-scoping}.}
   in Figure~\ref{fig:lexical-scoping}.}
-\label{fig:tuple-rep}
+\label{fig:closures}
+\end{figure}
+
+
+\section{Interpreting $R_5$}
+
+Figure~\ref{fig:interp-R5} shows the definitional interpreter for
+$R_5$. There are several things to worth noting. First, and most
+importantly, the match clause for \key{lambda} saves the current
+environment inside the returned \key{lambda}. Then the clause for
+\key{app} uses the environment from the \key{lambda}, the
+\code{lam-env}, when interpreting the body of the \key{lambda}.  Of
+course, the \code{lam-env} environment is extending with the mapping
+parameters to argument values. To enable mutual recursion and allow a
+unified handling of functions created with \key{lambda} and with
+\key{define}, the match clause for \key{program} includes a second
+pass over the top-level functions to set their environments to be the
+top-level environment.
+
+\begin{figure}[tbp]
+\begin{lstlisting}
+(define (interp-R5 env)
+  (lambda (ast)
+    (match ast
+       [`(lambda: ([,xs : ,Ts] ...) : ,rT ,body)
+        `(lambda ,xs ,body ,env)]
+       [`(app ,fun ,args ...)
+        (define arg-vals (map (interp-R5 env) args))
+        (define fun-val ((interp-R5 env) fun))
+        (match fun-val
+           [`(lambda (,xs ...) ,body ,lam-env)
+            (define new-env (append (map cons xs arg-vals) lam-env))
+            ((interp-R5 new-env) body)]
+           [else (error "interp-R5, expected function, not" fun-val)])]
+       [`(define (,f [,xs : ,ps] ...) : ,rt ,body)
+        (mcons f `(lambda ,xs ,body))]
+       [`(program ,defs ... ,body)
+        (let ([top-level (map (interp-R5 '()) defs)])
+          (for/list ([b top-level])
+                    (set-mcdr! b (match (mcdr b)
+                                   [`(lambda ,xs ,body)
+                                    `(lambda ,xs ,body ,top-level)])))
+          ((interp-R5 top-level) body))]
+       ...)))
+\end{lstlisting}
+\caption{Definitional interpreter for $R_5$.}
+\label{fig:interp-R5}
 \end{figure}
 \end{figure}
 
 
+\section{Type Checking $R_5$}
+
+Figure~\ref{fig:typecheck-R5} shows how to type check the new
+\key{lambda} form. The body of the \key{lambda} is checked in an
+environment that includes the current environment (because it is
+lexically scoped) and also includes the \key{lambda}'s parameters.  We
+require the body's type to match the declared return type.
+
+\begin{figure}[tbp]
+\begin{lstlisting}
+(define (typecheck-R5 env)
+  (lambda (e)
+    (match e
+      [`(lambda: ([,xs : ,Ts] ...) : ,rT ,body)
+       (define new-env (append (map cons xs Ts) env))
+       (define bodyT ((typecheck-R5 new-env) body))
+       (cond [(equal? rT bodyT)
+              `(,@Ts -> ,rT)]
+             [else
+              (error "mismatch in return type" bodyT rT)])]
+      ...
+      )))
+\end{lstlisting}
+\caption{Type checking the \key{lambda}'s in $R_5$.}
+\label{fig:typecheck-R5}
+\end{figure}
+
+
+\section{Closure Conversion}
+
+The compiling of lexically-scoped functions into $R_4$-style functions
+is accomplished in the pass \code{convert-to-closures} that comes
+after \code{reveal-functions} and before flatten. This pass needs to
+treat regular function calls differently from applying primitive
+operators, and \code{reveal-functions} differentiates those two cases
+for us.
 
 
+As usual, we shall implement the pass as a recursive function over the
+AST. All of the action is in the clauses for \key{lambda} and
+\key{app} (function application). We transform a \key{lambda}
+expression into an expression that creates a closure, that is, creates
+a vector whose first element is the function pointer and the rest of
+the elements are the values of the free variables.
+
+\begin{tabular}{lll}
+\begin{minipage}{0.4\textwidth}
+\begin{lstlisting}
+(lambda: (|\itm{ps}| ...) : |\itm{rt}| |\itm{body}|)
+\end{lstlisting}
+\end{minipage}
+&
+$\Rightarrow$
+&
+\begin{minipage}{0.4\textwidth}
+\begin{lstlisting}
+(vector |\itm{name}| |\itm{fvs}| ...)
+\end{lstlisting}
+\end{minipage}
+\end{tabular}  \\
+
+\begin{lstlisting}
+(define (|\itm{name}| [clos : _] |\itm{ps}| ...)
+   (let ([|$\itm{fvs}_1$| (vector-ref clos 1)])
+     ...
+     (let ([|$\itm{fvs}_n$| (vector-ref clos $n$)])
+       |\itm{body'}|)...))
+\end{lstlisting}
 
 
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

BIN
closures.pdf