【问题标题】:In Lisp, code is data. What benefit does that provide?在 Lisp 中,代码就是数据。这有什么好处?
【发布时间】:2011-04-29 13:59:54
【问题描述】:

在 Lisp 中,任何程序的代码实际上都是有效的数据结构。例如,这将 1 和 2 相加,但它也是一个包含三个项目的列表。

(+ 1 2)

这有什么好处?是什么让您能够做到在其他语言中是不可能和/或不太优雅的?

【问题讨论】:

  • 这可能会被当作骗子关闭...(stackoverflow.com/search?q=%5Blisp%5D+macros) 这是维基百科上相关的 sn-p:en.wikipedia.org/wiki/… Peter Seibel 的 Practical Common Lisp 是对 Common Lisp 的一个非常好的介绍并包括演示宏的早期章节:gigamonkeys.com/book/practical-a-simple-database.html
  • 这个问题似乎倒退了:你正在接受 Lisp 设计的结果并询问如何处理它。在实践中,我从做事开始。 (在 Java 中,一个 int 是 32 位的——这有什么好处?好吧,我们可能可以列出一些,但它们看起来很人为,因为没有 Java 程序员会从这个方向考虑它。)
  • @Ken 我肯定知道你来自哪里。但是,出于好奇,我问这个问题。我已经在用其他语言做事,而且我从来没有觉得我的代码需要成为数据。我只是想知道我错过了什么,Eli 做了很棒的解释。

标签: lisp


【解决方案1】:

为了让代码表示更清楚一点,请考虑在每一种语言中,代码都是数据:您需要的只是字符串。 (也许还有一些文件操作。)考虑如何帮助您模仿 Lisp 拥有宏系统的好处是一种启蒙的好方法。如果您尝试实现这样的宏系统,那就更好了。您将遇到结构化表示与字符串扁平化的优势,首先需要运行转换并定义“句法挂钩”来告诉您在哪里应用它们等等。

但是您将在所有这些中看到的主要内容是,宏本质上是编译器挂钩的便利工具——挂钩新创建的关键字的工具。因此,唯一真正需要的是让用户代码与编译器代码交互的某种方式。扁平字符串是一种方法,但它们提供的信息太少,以至于宏编写者只能从头开始实现解析器。另一方面,您可以公开一些内部编译器结构,例如预解析的 AST 树,但这些往往会公开太多信息以方便使用并且这意味着编译器需要以某种方式能够解析您打算实现的新语法扩展。 S 表达式是后者的一个很好的解决方案:编译器可以解析任何东西,因为语法是统一的。它们也是前者的解决方案,因为它们是简单的结构,并得到语言的丰富支持,可以将它们分开并以新的方式重新组合。

但这当然不是故事的结局。例如,比较 CL 中的普通符号宏和 Scheme 实现中的卫生宏很有趣:它们通常通过向表示的数据添加更多信息来实现,这意味着您可以使用这些宏系统做更多事情。 (您还可以使用 CL 宏做更多事情,因为额外的信息也可用,但不是将其作为语法表示的一部分,而是作为额外的环境参数传递给宏。)

【讨论】:

  • 这是一个很棒的解释。谢谢!
【解决方案2】:

我最喜欢的例子...在大学里,我的一些朋友正在用 Lisp 编写编译器。所以他们所有的数据结构,包括解析树都是 lisp s-expressions。到了实现代码生成阶段的时候,他们只需执行解析树即可。

【讨论】:

    【解决方案3】:

    它允许您编写简单地将一棵列表树转换为另一棵树的宏。简单(方案)示例:

    (define-syntax and
      (syntax-rules ()
       ((and) #t)
       ((and thing) thing)
       ((and thing rest ...) (if thing (and rest ...) #f))))
    

    注意宏调用是如何与(and)(and thing)(and thing rest ...) 子句简单匹配的(取决于调用的数量),并得到适当的处理。

    对于其他语言,宏必须处理正在转换的代码的某种内部 AST——否则就没有一种简单的方法可以以编程格式“查看”您的代码——而且会增加编写宏的摩擦。

    在 Lisp 程序中,宏通常使用得非常频繁,正是因为编写它们的阻力小。

    【讨论】:

      【解决方案4】:

      Lisp 是为处理各种符号数据而开发的。事实证明,人们也可以将任何 Lisp 程序视为符号数据。因此,您可以将 Lisp 的操作功能应用到自身。

      如果你想用程序进行计算(创建新程序、将程序编译为机器代码、将程序从 Lisp 翻译成其他语言),基本上有三种选择:

      • 使用字符串。这让解析和反解析字符串一直很繁琐。

      • 使用解析树。有用但变得复杂。

      • 使用 Lisp 中的符号表达式。程序被预先解析为熟悉的数据结构(列表、符号、字符串、数字……),并且操作例程以常用语言提供的功能编写。

      那么你用 Lisp 得到了什么?编写操作其他程序的程序的一种相对简单的方法。从宏到编译器有很多这样的例子。您还可以轻松地将语言嵌入到 Lisp 中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多