The introduction to the Scheme programming language definition establishes this design principle:
Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary.
以下是到37頁為止的解釋器骡男,無閉包,會(huì)導(dǎo)致dynamic scoping。
In other words, we’re again failing to faithfully capture what substitution would have done. A function value needs to remember the substitutions that have already been applied to it. Because we’re representing substitutions using an environment, a function value therefore needs to be bundled with an environment. This resulting data structure is called a closure.
#lang plai-typed
(define-type Value
[numV (n : number)]
[funV (name : symbol) (arg : symbol) (body : ExprC)])
(define-type ExprC
[numC (n : number)]
[idC (s : symbol)]
[appC (fun : ExprC) (arg : ExprC)]
[plusC (l : ExprC) (r : ExprC)]
[multC (l : ExprC) (r : ExprC)]
[fdC (name : symbol) (arg : symbol) (body : ExprC)])
(define (lookup [n : symbol] [env : Env]) : Value
(cond
[(empty? env) (error 'lookup "Symbol not found in env")]
[(cons? env) (cond
[(equal? n (bind-name (first env))) (bind-val (first env))]
[else (lookup n (rest env))])]))
(define-type Binding
[bind (name : symbol) (val : Value)])
(define-type-alias Env (listof Binding))
(define mt-env empty)
(define extend-env cons)
(define (num+ [l : Value] [r : Value]) : Value
(cond
[(and (numV? l) (numV? r))
(numV (+ (numV-n l) (numV-n r)))]
[else
(error 'num+ "one argument was not a number")]))
(define (num* [l : Value] [r : Value]) : Value
(cond
[(and (numV? l) (numV? r))
(numV (* (numV-n l) (numV-n r)))]
[else
(error 'num* "one argument was not a number")]))
(define (interp [expr : ExprC] [env : Env]) : Value
(type-case ExprC expr
[numC (n) (numV n)]
[idC (n) (lookup n env)]
[plusC (l r) (num+ (interp l env) (interp r env))]
[multC (l r) (num* (interp l env) (interp r env))]
[fdC (n a b) (funV n a b)]
[appC (f a) (local ([define fd (interp f env)])
(interp (funV-body fd)
(extend-env (bind (funV-arg fd)
(interp a env))
mt-env)))]))
改為帶closure的
#lang plai-typed
(define-type Value
[numV (n : number)]
[closV (arg : symbol) (body : ExprC) (env : Env)])
(define-type ExprC
[numC (n : number)]
[idC (s : symbol)]
[appC (fun : ExprC) (arg : ExprC)]
[plusC (l : ExprC) (r : ExprC)]
[multC (l : ExprC) (r : ExprC)]
[lamC (arg : symbol) (body : ExprC)])
(define (lookup [n : symbol] [env : Env]) : Value
(cond
[(empty? env) (error 'lookup "Symbol not found in env")]
[(cons? env) (cond
[(equal? n (bind-name (first env))) (bind-val (first env))]
[else (lookup n (rest env))])]))
(define-type Binding
[bind (name : symbol) (val : Value)])
(define-type-alias Env (listof Binding))
(define mt-env empty)
(define extend-env cons)
(define (num+ [l : Value] [r : Value]) : Value
(cond
[(and (numV? l) (numV? r))
(numV (+ (numV-n l) (numV-n r)))]
[else
(error 'num+ "one argument was not a number")]))
(define (num* [l : Value] [r : Value]) : Value
(cond
[(and (numV? l) (numV? r))
(numV (* (numV-n l) (numV-n r)))]
[else
(error 'num+ "one argument was not a number")]))
(define (interp [expr : ExprC] [env : Env]) : Value
(type-case ExprC expr
[numC (n) (numV n)]
[idC (n) (lookup n env)]
[plusC (l r) (num+ (interp l env) (interp r env))]
[multC (l r) (num* (interp l env) (interp r env))]
[lamC (a b) (closV a b env)]
[appC (f a) (local ([define f-value (interp f env)])
(interp (closV-body f-value)
(extend-env (bind (closV-arg f-value)
(interp a env))
(closV-env f-value))))]))
Sugaring Over Anonymity
left-left-lambda
((lambda (double)
(double 10))
(lambda (x) (+ x x)))
;=>
(let ([double (lambda (x) (+ x x))])
(double 10))
7.4 Substitution, Again
(lambda (f)
(lambda (x)
(f 10)))
;其中f是
(lambda (y) (+ x y))
直接替換會(huì)導(dǎo)致dynamic scoping.
利用α-convention就缆。
(lambda (f1)
(lambda (x1)
(f1 10)))
(lambda (y1) (+ x y1))
(lambda (x1)
((lambda (y1) (+ x y1)) 10))
;x是未定義的自由變量匙监,正是期待的行為