LET与LET *在Common Lisp中

我理解LET和LET *(并行和顺序绑定)之间的区别,作为一个理论问题,它是完美的意义。但是有没有你真的需要LET的情况?在我最近看过的我所有的Lisp代码中,你可以用LET *替换每个LET,而不改变。

编辑:好吧,我明白为什么有些人发明了LET *,大概是一个宏,回来的时候。我的问题是,鉴于LET *存在,LET是否有理由留在身边?你写了任何实际的Lisp代码,其中LET *不能工作,以及一个简单的LET?

我不买的效率论证。首先,认识到LET *可以编译成与LET一样高效的情况,似乎并不难。第二,CL规范中有很多东西,似乎根本不是为了效率而设计的。 (什么时候是你最后一次看到一个类型声明的LOOP?那些是很难找出我从来没有见过他们使用。)在Dick Gabriel的20世纪80年代末的基准,CL是完全缓慢。

看起来这是另一个向后兼容的情况:明智的是,没有人想冒险打破像LET这样基本的东西。这是我的预感,但很安慰,听说没有人有一个愚蠢的简单案例,我失踪,LET做了一堆的事情比LET *容易得多。

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)

(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。

理查德·加布里埃尔在1985年发表了他的关于Lisp基准的书,当时这些基准也用于非CL Lisps。 Common Lisp本身在1985年是全新的 – CLtL1书描述的语言刚刚在1984年发布。难怪实施没有非常优化的时间。实现的优化基本上与以前的实现(如MacLisp)相同(或更少)。

但是对于LET和LET *,主要的区别是使用LET的代码对于人类更容易理解,因为绑定条款彼此独立 – 特别是因为它是利用左到右评估的不良风格(不是设置变量作为副作用)。

翻译自:https://stackoverflow.com/questions/554949/let-versus-let-in-common-lisp

转载注明原文:LET与LET *在Common Lisp中