Sha*_*nce 3 lambda scheme factorial let
考虑以下函数来实现计算阶乘:[1]
(define fac-tail
(lambda (n)
(define fac-tail-helper
(lambda (n ac)
(if (= 0 n)
ac
(fac-tail-helper (- n 1) (* n ac)))))
(fac-tail-helper n 1)))
Run Code Online (Sandbox Code Playgroud)
我试图用let内部定义重写:
(define fac-tail-2
(lambda (n)
(let ((fac-tail-helper-2
(lambda (n ac)
(if (= 0 n)
ac
(fac-tail-helper-2 (- n 1) (* n ac))))))
(fac-tail-helper-2 n 1))))
Run Code Online (Sandbox Code Playgroud)
define时间没有错误,但执行结果为:
#;> (fac-tail-2 4)
Error: undefined variable 'fac-tail-helper-2'.
{warning: printing of stack trace not supported}
Run Code Online (Sandbox Code Playgroud)
如何使let版本有效?
方案版本是SISC v 1.16.6
[1]基于factorialSICP第1.2.1节的迭代版本http://mitpress.mit.edu/sicp/full-text/book/book-ZH-11.html#%_sec_1.2.1
R. Kent Dvbvig说:
事实上,let表达式是根据lambda和过程应用定义的语法扩展,它们都是核心句法形式.一般来说,任何形式的表达
(let ((var expr) ...) body1 body2 ...)
Run Code Online (Sandbox Code Playgroud)
相当于以下内容.
((lambda (var ...) body1 body2 ...)
expr ...)" [1]
Run Code Online (Sandbox Code Playgroud)
这意味着fac-tail-2相当于:
(define fac-tail-2
(lambda (n)
((lambda (fac-tail-helper-2)
(fac-tail-helper-2 n 1)) ;; <== scope where fac-tail-helper-2 is visible.
(lambda (n ac) ;; this lambda is assigned to fac-tail-helper-2
(if (= 0 n)
ac
(fac-tail-helper-2 (- n 1) (* n ac))))))) ;; <=== problem
Run Code Online (Sandbox Code Playgroud)
并且很明显,问题是fac-tail-helper-2名称在lambda上面突出显示的主体中作为参数可见,但不是lambda指定给参数的名称fac-tail-helper-2.
[1]第2.5节,方案编程语言的 "Lambda表达式" ,第4版http://scheme.com/tspl4/start.html#SECTGSLAMBDA