关闭。这个问题需要更多focused .它目前不接受答案。
想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post .
3个月前关闭。
Improve this question
我需要一些帮助来理解 Paul Graham 的一些观点 What Made Lisp Different .
这些点是什么意思?它们在 C 或 Java 等语言中有何不同?除了 Lisp 家族语言之外,现在还有其他语言有这些结构吗?
最佳答案
Matt 的解释非常好——他尝试与 C 和 Java 进行比较,我不会这样做——但出于某种原因,我真的很喜欢偶尔讨论这个话题,所以——这是我的镜头在一个答案。
关于第 (3) 和 (4) 点:
您列表中的第 (3) 和 (4) 点似乎最有趣,现在仍然相关。
要理解它们,清楚地了解 Lisp 代码(以程序员输入的字符流的形式)在执行过程中发生了什么是很有用的。让我们使用一个具体的例子:
;; a library import for completeness,
;; we won't concern ourselves with it
(require '[clojure.contrib.string :as str])
;; this is the interesting bit:
(println (str/replace-re #"\d+" "FOO" "a123b4c56"))
Clojure的这个片段代码打印出来 aFOObFOOcFOO
.请注意,Clojure 可以说并不完全满足您列表中的第四点,因为读取时间并不是真正对用户代码开放;不过,我将讨论否则这意味着什么。因此,假设我们将这段代码放在某个文件中,并要求 Clojure 执行它。另外,让我们假设(为了简单起见)我们已经通过了库导入。有趣的一点开始于
(println
并在 )
结束右边很远。这正如人们所期望的那样被词法/解析,但已经出现了一个重要的问题:结果不是一些特殊的编译器特定的 AST 表示——它只是一个常规的 Clojure/Lisp 数据结构 ,即一个嵌套列表,包含一堆符号、字符串和——在本例中——与 #"\d+"
对应的单个编译的正则表达式模式对象。文字(更多关于这个下面)。一些 Lisp 在这个过程中添加了他们自己的小曲折,但 Paul Graham 主要指的是 Common Lisp。在与您的问题相关的点上,Clojure 类似于 CL。编译时的整个语言:
在这一点之后,所有编译器处理(对于 Lisp 解释器也是如此;Clojure 代码总是被编译)是 Lisp 程序员习惯于操作的 Lisp 数据结构。在这一点上,一个绝妙的可能性变得明显:为什么不让 Lisp 程序员编写 Lisp 函数来处理表示 Lisp 程序的 Lisp 数据并输出表示转换后的程序的转换数据,以代替原始程序?换句话说——为什么不允许 Lisp 程序员将他们的函数注册为各种编译器插件,在 Lisp 中称为宏?事实上,任何体面的 Lisp 系统都具有这种能力。
因此,宏是常规的 Lisp 函数,在编译时对程序的表示进行操作,在最终编译阶段发出实际目标代码之前。由于宏允许运行的代码种类没有限制(特别是,它们运行的代码本身通常是自由使用宏工具编写的),可以说“整个语言在编译时可用”。
阅读时的整个语言:
让我们回到那个
#"\d+"
正则表达式。如上所述,在编译器听到第一次提到准备编译的新代码之前,它会在读取时转换为实际的编译模式对象。这是怎么发生的?好吧,Clojure 当前的实现方式,与 Paul Graham 的想法有些不同,尽管使用 a clever hack 一切皆有可能。 .在 Common Lisp 中,故事在概念上会稍微清晰一些。然而,基本原理是相似的:Lisp Reader 是一个状态机,除了执行状态转换并最终声明它是否已达到“接受状态”之外,还会吐出字符所代表的 Lisp 数据结构。因此字符
123
成为号码123
等等。重点来了:这个状态机可以通过用户代码修改 . (如前所述,在 CL 的情况下完全正确;对于 Clojure,需要进行 hack(不鼓励且未在实践中使用)。但我离题了,我应该详细阐述 PG 的文章,所以...)所以,如果你是一名 Common Lisp 程序员,并且碰巧喜欢 Clojure 风格的向量字面量的想法,你可以向阅读器插入一个函数来对某些字符序列做出适当的 react ——
[
或 #[
可能 -- 并将其视为以匹配 ]
结尾的向量字面量的开始.这样的函数称为读取器宏,就像普通宏一样,它可以执行任何类型的 Lisp 代码,包括使用先前注册的读取器宏启用的时髦符号编写的代码。所以在阅读时有完整的语言供您使用。总结一下:
实际上,到目前为止已经证明的是,可以在读取时或编译时运行常规的 Lisp 函数;从这里开始理解读取和编译本身如何在读取、编译或运行时成为可能的第一步是认识到读取和编译本身是由 Lisp 函数执行的。您只需拨打
read
或 eval
随时从字符流中读入 Lisp 数据或分别编译和执行 Lisp 代码。这就是整个语言,一直在那里。请注意,Lisp 满足列表中的第 (3) 点这一事实对于它设法满足第 (4) 点的方式至关重要——Lisp 提供的宏的特殊风格严重依赖于由常规 Lisp 数据表示的代码,这是由(3)启用的。顺便说一句,这里只有代码的“树状”方面才是真正重要的——可以想象,您可以使用 XML 编写 Lisp。
关于clojure - 请解释 Paul Graham 关于 Lisp 的一些观点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2710231/