当前位置:  开发笔记 > 编程语言 > 正文

Common Lisp中的LET与LET*

如何解决《CommonLisp中的LET与LET*》经验,为你挑选了7个好方法。

我理解LET和LET*之间的区别(并行与顺序绑定),作为理论问题,它非常有意义.但有没有你真的需要LET的情况?在我最近看过的所有Lisp代码中,您可以用LET*替换每个LET而不做任何更改.

编辑:好的,我理解为什么有些人发明了LET*,大概是作为一个宏,回归的时候.我的问题是,鉴于LET*存在,是否有理由让LET留在身边?您是否编写了任何实际的Lisp代码,其中LET*不能像普通的LET那样工作?

我不买效率论证.首先,认识到LET*可以编译成像LET一样高效的情况,这似乎并不难.其次,CL规范中有很多东西似乎根本就不是围绕效率而设计的.(当你最后一次看到带有类型声明的循环时?那些很难弄清楚我从未见过它们使用过.)在20世纪80年代后期的Dick Gabriel基准测试之前,CL 非常缓慢.

看起来这是另一种向后兼容的情况:明智的是,没有人愿意冒险破坏像LET那样基本的东西.这是我的预感,但是听到没有人有一个我丢失的愚蠢简单的案例令人欣慰,因为LET比LET*更容易让事情变得简单.



1> Rainer Joswi..:

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为a fixnum.

Richard P. Gabriel在1985年发表了关于Lisp基准测试的书,当时这些基准测试也用于非CL Lisps.Common Lisp本身在1985年是全新的 - CLtL1书中描述了该语言刚刚于1984年出版.难怪当时的实现并没有得到很好的优化.实现的优化与之前的实现基本相同(或更少)(如MacLisp).

LETLET*主要的区别是使用的代码LET更容易理解对于人类来说,由于约束力的条款是相互独立的-尤其是因为它是坏的风格趁从左到右评估(未设置变量的一个侧面影响).


不,不!Lambda不是真正的原语,因为它可以用LET替换,而低级lambda只提供API来获取参数值:`(低级-lambda 2(let((x(car%args%) ))(y(cadr args)))...)`:)

2> Mr Fooz..:

不需要 LET,但你通常需要它.

LET表明你只是做标准的并行绑定而没有任何棘手的事情.LET*引起对编译器的限制,并向用户建议有必要进行顺序绑定的原因.在风格方面,当您不需要LET*施加的额外限制时,LET会更好.

使用LET比使用LET*更高效(取决于编译器,优化器等):

并行绑定可以并行执行(但我不知道是否有任何LISP系统实际执行此操作,并且init表单仍必须按顺序执行)

并行绑定为所有绑定创建单个新环境(范围).顺序绑定为每个单独的绑定创建一个新的嵌套环境.并行绑定使用更少的内存并具有更快的变量查找.

(上述要点适用于Scheme,另一种LISP方言.clisp可能有所不同.)


并行执行不是Common Lisp标准以任何方式处理的事情.更快的变量查找也是一个神话.
注意:请参阅[此答案](http://stackoverflow.com/a/562975/313756)(和/或hyperspec的链接部分),了解您的第一个后备点的原因 - 误导,让我们说._bindings_并行发生,但_forms_按顺序执行 - 按规范执行.

3> Logan Capald..:

我带来了人为的例子.比较结果:

(print (let ((c 1))
         (let ((c 2)
               (a (+ c 1)))
           a)))

运行结果:

(print (let ((c 1))
         (let* ((c 2)
                (a (+ c 1)))
           a)))


@John:在第一个例子中,`a`的绑定指的是`c`的外部值.在第二个例子中,`let*`允许绑定引用先前的绑定,`a`的绑定指的是`c`的内部值.洛根并不是在说这是一个人为的例子,它甚至没有假装有用.此外,缩进是非标准和误导性的.在两者中,`a`的绑定应该是一个空格,与`c`排列,内部`let`的'body'应该只是'let`本身的两个空格.
这个答案提供了重要的见解.当一个人想要_avoid_具有二级绑定(我只是意味着不是第一个)时,会特别**使用`let`引用第一个绑定,但是你想要隐藏一个先前的绑定 - 使用前一个初始化一个辅助绑定的值.
关心开发为什么会这样?

4> David Thornl..:

在LISP中,通常需要使用最弱的构造.例如,某些样式指南会告诉您使用=而不是eql当您知道比较的项目是数字时.这个想法通常是指明你的意思,而不是有效地编程计算机.

但是,只能说出你的意思,而不是使用更强大的结构,可以实际提高效率.如果使用了初始化LET,则可以并行执行,而LET*初始化必须按顺序执行.我不知道是否有任何实现实际上会这样做,但有些可能在未来.


好点子.虽然Lisp是一种高级语言,但这让我想知道为什么"最弱的构造"在Lisp土地上是如此理想的风格.你没有看到Perl程序员说"好吧,我们不需要*在这里使用regexp ......":-)
你所指的原则是使用*最强*适用的原语,而不是*最弱*.例如,如果要比较的东西是符号,请使用`eq`.或者,如果您知道要分配给符号位置,请使用`setq`.但是,这个原则也被我的许多Lisp程序员拒绝了,他们只想要一个没有过早优化的高级语言.

5> 小智..:

LET和LET*之间的公共列表的主要区别在于LET中的符号是并行绑定的,而LET*中的符号是顺序绑定的.使用LET不允许init-forms并行执行,也不允许更改init-forms的顺序.原因是Common Lisp允许函数产生副作用.因此,评估的顺序很重要,并且在表格中始终是从左到右.因此,在LET中,首先从左到右评估init-forms,然后并行地从左到右创建绑定.在LET*中,初始形式被评估,然后从左到右依次绑定到符号.

CLHS:特别运营商LET,LET*


似乎这个答案可能是对[这个答案](http://stackoverflow.com/a/555136/313756)的回应所吸取的一些能量?另外,根据规范链接,_bindings_被称为在"LET"中并行完成,即使你正确地指出init-forms是串行执行的.在现有的任何实施中,这是否有任何实际差异,我不知道.

6> Samuel Edwin..:

我最近编写了两个参数的函数,如果我们知道哪个参数更大,那么算法表达得最清楚.

(defun foo (a b)
  (let ((a (max a b))
        (b (min a b)))
    ; here we know b is not larger
    ...)
  ; we can use the original identities of a and b here
  ; (perhaps to determine the order of the results)
  ...)

假设b更大,如果我们使用let*,我们会不小心设置ab相同的值.



7> Attila Lendv..:

我走一步,并使用绑定统一了let,let*,multiple-value-bind,destructuring-bind等,它甚至扩展.

一般来说,我喜欢使用"最弱的构造",但不喜欢let和朋友一起使用,因为它们只是给代码带来了噪音(主观性警告!不需要试着说服我相反的......)

推荐阅读
黄晓敏3023
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有