Common Lisp中的LET与LET * [英] LET versus LET* in Common Lisp

查看:207
本文介绍了Common Lisp中的LET与LET *的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我了解LET和LET *(并行绑定和顺序绑定)之间的区别,从理论上讲,它是很有意义的.但是,在任何情况下,您实际需要LET吗?在我最近查看的所有Lisp代码中,您可以将所有LET替换为LET *,而无需进行任何更改.

I understand the difference between LET and LET* (parallel versus sequential binding), and as a theoretical matter it makes perfect sense. But is there any case where you've ever actually needed LET? In all of my Lisp code that I've looked at recently, you could replace every LET with LET* with no change.

好的,我知道为什么为什么有人发明了LET *(大概是宏),可以追溯到何时.我的问题是,考虑到LET *的存在,LET有理由留在身边吗?您是否编写了任何实际的Lisp代码,而LET *不能像普通的LET一样有效?

OK, I understand why some guy invented LET*, presumably as a macro, way back when. My question is, given that LET* exists, is there a reason for LET to stay around? Have you written any actual Lisp code where a LET* would not work as well as a plain LET?

我不赞成效率论点.首先,认识到可以将LET *编译成与LET一样高效的情况似乎并不难.其次,CL规范中有很多东西似乎根本不是围绕效率而设计的. (您上次看到带类型声明的LOOP是什么时候?这些是如此难以理解,我从未见过它们使用过.)在Dick Gabriel于1980年代后期进行的基准测试之前,CL 一直很慢.

I don't buy the efficiency argument. First, recognizing cases where LET* can be compiled into something as efficient as LET just doesn't seem that hard. Second, there are lots of things in the CL spec that simply don't seem like they were designed around efficiency at all. (When's the last time you saw a LOOP with type declarations? Those are so hard to figure out I've never seen them used.) Before Dick Gabriel's benchmarks of the late 1980's, CL was downright slow.

这似乎是向后兼容的另一种情况:明智地,没有人愿意冒险破坏像LET这样基本的东西.这是我的直觉,但是令人欣慰的是,没有人错过如此愚蠢的案件,而LET使一堆事情比LET *容易得多.

It looks like this is another case of backwards compatibility: wisely, nobody wanted to risk breaking something as fundamental as LET. Which was my hunch, but it's comforting to hear that nobody has a stupidly-simple case I was missing where LET made a bunch of things ridiculously easier than LET*.

推荐答案

LET本身在 Functional Programming Language 中不是真正的原语,因为它可以替换为LAMBDA.像这样:

LET itself is not a real primitive in a Functional Programming Language, since it can replaced with LAMBDA. Like this:

(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*.

You can imagine which is the simpler thing. LET and not LET*.

LET使代码理解更加容易.一个人看到了一堆绑定,一个人可以分别读取每个绑定,而无需了解效果"(重新绑定)的自上而下/左右流动.使用LET*信号通知程序员(读取代码的人),绑定不是独立的,但是存在某种自上而下的流程-使事情复杂化.

LET makes code understanding easier. One sees a bunch of bindings and one can read each binding individually without the need to understand the top-down/left-right flow of 'effects' (rebindings). Using LET* signals to the programmer (the one that reads code) that the bindings are not independent, but there is some kind of top-down flow - which complicates things.

Common Lisp的规则是,LET中的绑定值从左到右计算.左右如何评估函数调用的值.因此,LET是概念上更简单的语句,并且默认情况下应使用它.

Common Lisp has the rule that the values for the bindings in LET are computed left to right. Just how the values for a function call are evaluated - left to right. So, LET is the conceptually simpler statement and it should be used by default.

LOOP 中的类型?经常使用.有些简单的类型声明形式很容易记住.示例:

Types in LOOP? Are used quite often. There are some primitive forms of type declaration that are easy to remember. Example:

(LOOP FOR i FIXNUM BELOW (TRUNCATE n 2) do (something i))

上面将变量i声明为fixnum.

Richard P. Gabriel于1985年出版了有关Lisp基准的书,当时这些基准也与非CL Lisps一起使用. Common Lisp本身在1985年是全新的-描述该语言的 CLtL1 书刚刚在1984年出版.难怪当时的实现方式还没有非常优化.实现的优化与以前的实现(例如MacLisp)基本相同(或更小).

Richard P. Gabriel published his book on Lisp benchmarks in 1985 and at that time these benchmarks were also used with non-CL Lisps. Common Lisp itself was brand new in 1985 - the CLtL1 book which described the language had just been published in 1984. No wonder the implementations were not very optimized at that time. The optimizations implemented were basically the same (or less) that the implementations before had (like MacLisp).

但是对于LETLET*而言,主要区别在于,使用LET的代码对于人类而言更易于理解,因为绑定子句彼此独立-尤其是因为利用此子句的风格很差从左到右的评估(不将变量设置为副作用).

But for LET vs. LET* the main difference is that code using LET is easier to understand for humans, since the binding clauses are independent of each other - especially since it is bad style to take advantage of the left to right evaluation (not setting variables as a side effect).

这篇关于Common Lisp中的LET与LET *的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆