LET
本身并不是一个真正的原语函数式编程语言,因为它可以替换为LAMBDA
。像这样:
(let ((a1 b1) (a2 b2) ... (an bn))
(some-code a1 a2 ... an))
类似于
((lambda (a1 a2 ... an)
(some-code a1 a2 ... an))
b1 b2 ... bn)
But
(let* ((a1 b1) (a2 b2) ... (an bn))
(some-code a1 a2 ... an))
类似于
((lambda (a1)
((lambda (a2)
...
((lambda (an)
(some-code a1 a2 ... an))
bn))
b2))
b1)
你可以想象哪个是更简单的事情。LET
并不是LET*
.
LET
使代码理解更容易。人们会看到一堆绑定,并且可以单独读取每个绑定,而无需了解“效果”(重新绑定)的自上而下/左右流动。使用LET*
向程序员(读取代码的程序员)发出信号,表明绑定不是独立的,而是存在某种自上而下的流程 - 这使事情变得复杂。
Common Lisp 有一个规则,即绑定的值LET
从左到右计算。函数调用的值是如何计算的 - 从左到右。所以,LET
是概念上更简单的语句,应该默认使用它。
输入LOOP
?经常使用。有一些易于记住的类型声明的原始形式。例子:
(LOOP FOR i FIXNUM BELOW (TRUNCATE n 2) do (something i))
上面声明了变量i
成为一个fixnum
.
Richard P. Gabriel 于 1985 年出版了他关于 Lisp 基准测试的书,当时这些基准测试也用于非 CL Lisp。 Common Lisp 本身在 1985 年还是全新的——CLtL1描述该语言的书于 1984 年刚刚出版。难怪当时的实现不是很优化。实现的优化与之前的实现(如 MacLisp)基本相同(或更少)。
But for LET
vs. LET*
主要区别在于代码使用LET
对于人类来说更容易理解,因为绑定子句是相互独立的 - 特别是因为利用从左到右的评估(不将变量设置为副作用)是不好的风格。