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

标签 clojure scheme lisp common-lisp

关闭。这个问题需要更多focused .它目前不接受答案。












想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post .

3个月前关闭。



Improve this question




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

  • 变量的新概念。在 Lisp 中,所有变量都是有效的指针。值是有类型的,而不是变量,分配或绑定(bind)变量意味着复制指针,而不是它们指向的内容。
  • 一种符号类型。符号与字符串的不同之处在于您可以通过比较指针来测试相等性。
  • 使用符号树的代码表示法。
  • 整个语言始终可用。读取时、编译时和运行时之间没有真正的区别。您可以在阅读时编译或运行代码,在编译时阅读或运行代码,在运行时阅读或编译代码。

  • 这些点是什么意思?它们在 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 函数执行的。您只需拨打 readeval随时从字符流中读入 Lisp 数据或分别编译和执行 Lisp 代码。这就是整个语言,一直在那里。
    请注意,Lisp 满足列表中的第 (3) 点这一事实对于它设法满足第 (4) 点的方式至关重要——Lisp 提供的宏的特殊风格严重依赖于由常规 Lisp 数据表示的代码,这是由(3)启用的。顺便说一句,这里只有代码的“树状”方面才是真正重要的——可以想象,您可以使用 XML 编写 Lisp。

    关于clojure - 请解释 Paul Graham 关于 Lisp 的一些观点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2710231/

    相关文章:

    vector - 相交两个先验排序向量的惯用/高效Clojure方法?

    scheme - `if` 语句在 Scheme 中是如何工作的?

    macros - 有没有一种干净的方法可以将函数添加到动态创建的命名空间?

    lisp - 定车!并输入方案语言

    clojure - "Best Practice"用于使用 native 库的 clojure 库?

    logging - 如何抑制继承的项目 logback.xml 文件(单个项目中有 2 个 logback.xml)?

    maven - 如何在 Clojure 中使用本地依赖项?

    ruby - Lisp 和 Erlang 原子、Ruby 和 Scheme 符号。它们有多有用?

    javascript - 如何在 JavaScript 等动态语言中实现延续?

    lisp - 检查 Tic-Tac-Toe 中的胜利