请解释Paul Graham关于Lisp的一些观点

时间:2010-04-25 22:30:33

标签: lisp clojure scheme common-lisp paul-graham

我需要一些帮助来理解Paul Graham的What Made Lisp Different中的一些观点。

  1. 变量的新概念。在Lisp中,所有变量都是有效的指针。值是具有类型而不是变量的值,分配或绑定变量意味着复制指针,而不是它们指向的内容。

  2. 符号类型。符号与字符串的不同之处在于您可以通过比较指针来测试相等性。

  3. 使用符号树的代码表示法。

  4. 整个语言始终可用。读取时间,编译时和运行时之间没有真正的区别。您可以在编译时编译或运行代码,同时在运行时读取或运行代码。

  5. 这些观点意味着什么?它们在C或Java等语言中有何不同?除了Lisp系列语言以外,是否还有其他任何语言?

4 个答案:

答案 0 :(得分:97)

答案 1 :(得分:64)

1) 一个新的变量概念。在Lisp中,所有变量都是有效的指针。值是具有类型而不是变量的值,分配或绑定变量意味着复制指针,而不是它们指向的内容。

(defun print-twice (it)
  (print it)
  (print it))

'它'是一个变量。它可以绑定到任何值。没有限制,也没有与变量相关的类型。如果调用该函数,则不需要复制该参数。该变量类似于指针。它有一种方法可以访问绑定到变量的值。无需保留内存。我们在调用函数时可以传递任何数据对象:任何大小和任何类型。

数据对象具有“类型”,并且可以查询所有数据对象的“类型”。

(type-of "abc")  -> STRING

2) 符号类型。符号与字符串的不同之处在于您可以通过比较指针来测试相等性。

符号是具有名称的数据对象。通常,该名称可用于查找对象:

|This is a Symbol|
this-is-also-a-symbol

(find-symbol "SIN")   ->  SIN

由于符号是真实的数据对象,我们可以测试它们是否是同一个对象:

(eq 'sin 'cos) -> NIL
(eq 'sin 'sin) -> T

这允许我们例如用符号写一个句子:

(defvar *sentence* '(mary called tom to tell him the price of the book))

现在我们可以计算句子中THE的数量:

(count 'the *sentence*) ->  2

在Common Lisp中,符号不仅有名称,而且还可以包含值,函数,属性列表和包。因此,符号可用于命名变量或函数。属性列表通常用于将元数据添加到符号中。

3) 使用符号树的代码表示法。

Lisp使用其基本数据结构来表示代码。

列表(* 3 2)可以是数据和代码:

(eval '(* 3 (+ 2 5))) -> 21

(length '(* 3 (+ 2 5))) -> 3

树:

CL-USER 8 > (sdraw '(* 3 (+ 2 5)))

[*|*]--->[*|*]--->[*|*]--->NIL
 |        |        |
 v        v        v
 *        3       [*|*]--->[*|*]--->[*|*]--->NIL
                   |        |        |
                   v        v        v
                   +        2        5

4) 整个语言始终可用。读取时间,编译时和运行时之间没有真正的区别。您可以在编译时编译或运行代码,同时在运行时读取或编译代码。

Lisp提供READ函数READ,用于从文本读取数据和代码,LOAD用于加载代码,EVAL用于评估代码,COMPILE用于编译代码,PRINT用于将数据和代码写入文本。

这些功能始终可用。他们不会消失。他们可以成为任何计划的一部分。这意味着任何程序都可以读取,加载,评估或打印代码 -

它们在C或Java等语言方面有何不同?

这些语言不提供符号,代码作为数据或运行时评估数据作为代码。 C中的数据对象通常是无类型的。

LISP家族语言以外的任何其他语言现在都有这些结构吗?

许多语言都具备这些功能。

区别:

在Lisp中,这些功能被设计为语言,因此易于使用。

答案 2 :(得分:31)

对于第(1)和(2)点,他正在谈论历史。 Java的变量几乎相同,这就是为什么你需要调用.equals()来比较值。

(3)正在讨论S表达式。 Lisp程序是用这种语法编写的,与Java和C等特殊语法相比,它提供了许多优势,例如以比C宏或C ++模板更清晰的方式捕获宏中的重复模式,以及使用相同的核心列表操作代码您用于数据的操作。

(4)以C为例:该语言实际上是两种不同的子语言:if()和while()以及预处理器。您使用预处理器来保存不必一直重复自己,或者使用#if / #ifdef跳过代码。但是这两种语言都是完全不同的,你不能像编译时那样在编译时使用while()#if。

C ++使模板更糟糕。查看一些关于模板元编程的参考资料,它提供了一种在编译时生成代码的方法,对于非专家来说非常困难。此外,它实际上是一堆使用模板和宏的黑客和技巧,编译器无法提供一流的支持 - 如果你发出一个简单的语法错误,编译器无法给你一个明确的错误信息。

嗯,使用Lisp,你可以用一种语言完成所有这些。在第一天学习时,您可以使用相同的东西在运行时生成代码。这并不是说元编程是微不足道的,但对于第一类语言和编译器支持来说,它肯定更直接。

答案 3 :(得分:-3)

点(1)和(2)也适合Python。举一个简单的例子“a = str(82.4)”,解释器首先创建一个值为82.4的浮点对象。然后它调用一个字符串构造函数,然后返回一个值为'82 .4'的字符串。左侧的“a”仅仅是该字符串对象的标签。原始浮点对象是垃圾收集的,因为没有更多的引用它。

在Scheme中,所有内容都以类似的方式被视为对象。 Common Lisp我不太确定。我会尽量避免考虑C / C ++概念。当我试图了解Lisps的美丽简约时,他们让我慢慢减速。