我读过很多文章,说 LISP 可以动态重新定义语法,大概是用宏。我很好奇这实际上能走多远?你能否重新定义语言结构,使其成为另一种语言的编译器?例如,您能否将 LISP 的功能性质更改为更加面向对象的语法和语义,也许可以说让语法更接近 Ruby 之类的东西?

特别是,是否可以使用宏摆脱括号地狱?我已经学了足够多的 (Emacs-)LISP 来用我自己的微功能定制 Emacs,但我很好奇宏在定制语言方面能走多远。

有帮助吗?

解决方案

这是一个非常好的问题。

我认为这是微妙的,但绝对可以回答:

宏不会陷入 s 表达式中。请参阅 LOOP 宏,了解使用关键字(符号)编写的非常复杂的语言。因此,虽然您可以用括号开始和结束循环,但它内部有自己的语法。

例子:

(loop for x from 0 below 100
      when (even x)
      collect x)

话虽这么说,大多数简单的宏只使用 s 表达式。而且你会“卡住”使用它们。

但正如 Sergio 所回答的那样,s 表达式开始感觉正确。语法不再碍事,您开始在语法树中编码。

至于阅读器宏,是的,你可以这样写:

#R{
      ruby.code.goes.here
  }

但您需要编写自己的 Ruby 语法解析器。

您还可以使用编译为现有 Lisp 结构的宏来模仿一些 Ruby 结构,例如块。

#B(some lisp (code goes here))

会翻译成

(lambda () (some lisp (code goes here)))

这一页 如何做到这一点。

其他提示

是的,你可以重新定义语法,让 Lisp 成为一个编译器。您可以使用“读取器宏”来完成此操作,它与您可能想到的普通“编译器宏”不同。

Common Lisp 具有内置功能,可以为读取器定义新语法,并使用读取器宏来处理该语法。此处理是在读取时完成的(在编译或评估时间之前)。要了解有关在 Common Lisp 中定义读取器宏的更多信息,请参阅 Common Lisp Hyperspec ——您需要阅读 章。2、《语法》章。23、《朗读者》. 。(我相信Scheme有相同的设施,但我不太熟悉它——请参阅 方案来源 为了 弧形编程语言).

作为一个简单的例子,假设您希望 Lisp 使用花括号而不是圆括号。这需要类似以下读者定义:

;; { and } become list delimiters, along with ( and ).
(set-syntax-from-char #\{ #\( )
(defun lcurly-brace-reader (stream inchar) ; this was way too easy to do.
  (declare (ignore inchar))
  (read-delimited-list #\} stream t))
(set-macro-character #\{ #'lcurly-brace-reader)

(set-macro-character #\} (get-macro-character #\) ))
(set-syntax-from-char #\} #\) )

;; un-lisp -- make parens meaningless
(set-syntax-from-char #\) #\] ) ; ( and ) become normal braces
(set-syntax-from-char #\( #\[ )

你告诉 Lisp,{ 就像一个 ( 而 } 就像一个 )。然后你创建一个函数(lcurly-brace-reader) 每当读者看到 { 时就会调用它,并且您使用 set-macro-character 将该函数分配给 {.然后你告诉 Lisp ( 和 ) 就像 [ 和 ] (也就是说,没有意义的语法)。

您可以做的其他事情包括,例如, 创建新的字符串语法 或使用 [ 和 ] 括起固定表示法并将其处理为 S 表达式。

您还可以远远超出此范围,使用您自己的宏字符重新定义整个语法,这将触发阅读器中的操作,因此天空确实是极限。这只是原因之一 保罗·格雷厄姆其他的 一直说 Lisp 是一种编写编译器的好语言。

我不是 Lisp 专家,哎呀,我什至不是 Lisp 程序员,但在对这种语言进行了一些实验之后,我得出的结论是,一段时间后,括号开始变得“​​不可见”,你开始将代码视为你希望如此。您开始更多地关注通过 s-exprs 和宏创建的语法结构,而不是列表和括号文本的词汇形式。

如果您利用一个好的编辑器来帮助进行缩进和语法着色(尝试将括号设置为与背景非常相似的颜色),则尤其如此。

您可能无法完全替换该语言并获得“Ruby”语法,但您不需要它。由于语言的灵活性,如果您愿意,您可以最终拥有一种感觉就像您遵循“Ruby 编程风格”的方言,无论这对您意味着什么。

我知道这只是一个经验观察,但我想当我意识到这一点时,我经历了 Lisp 启蒙时刻之一。

一遍又一遍地,LISP的新来者想“摆脱所有括号”。它持续了几周。没有一个项目可以在通常的S-表达解析器上构建严重的通用编程语法,因为程序员总是会偏爱您当前认为是“括号般的地狱”。它需要一些习惯,但不多!一旦你习惯了它,并且你可以真正体会到默认语法的可塑性,回到只有一种方法来表达任何特定编程结构的语言真的很令人烦恼。

话虽这么说,Lisp 是构建领域特定语言的绝佳基础。即使不比 XML 更好,也和 XML 一样好。

祝你好运!

我见过的 Lisp 宏的最好解释是

https://www.youtube.com/watch?v=4NO83wZVT0A

大约55分钟开始。这是 Peter Seibel 的演讲视频,他是《Practical Common Lisp》的作者,这是最好的 Lisp 教科书。

Lisp 宏的动机通常很难解释,因为它们确实在太长而无法在简单教程中呈现的情况下发挥作用。彼得举了一个很好的例子;你可以完全掌握它,并且它很好地、正确地使用了 Lisp 宏。

你问:“你能否将 LISP 的功能性质更改为更加面向对象的语法和语义”。答案是肯定的。事实上,Lisp 最初根本没有任何面向对象编程,这并不奇怪,因为 Lisp 早在面向对象编程之前就已经存在了!但是,当我们在 1978 年第一次了解 OOP 时,我们能够使用宏等方式轻松地将其添加到 Lisp 中。最终,Common Lisp 对象系统 (CLOS) 被开发出来,这是一个非常强大的面向对象编程系统,非常适合 Lisp。整个东西可以作为扩展加载——没有任何东西是内置的!这一切都是通过宏完成的。

Lisp 有一个完全不同的功能,称为“阅读器宏”,可用于扩展语言的表面语法。使用阅读器宏,您可以创建具有类似 C 或 Ruby 语法的子语言。他们在内部将文本转换为 Lisp。这些并没有被大多数真正的 Lisp 程序员广泛使用,主要是因为很难扩展交互式开发环境来理解新语法。例如,Emacs 缩进命令可能会因新语法而混淆。不过,如果您精力充沛,Emacs 也是可扩展的,您可以教它新的词汇语法。

常规宏对对象列表进行操作。最常见的是,这些对象是其他列表(从而形成树)和符号,但它们也可以是其他对象,例如字符串、哈希表、用户定义的对象等。这些结构称为 s-exps.

因此,当您加载源文件时,Lisp 编译器将解析文本并生成 s-exp。宏对这些进行操作。这非常有效,并且是在 s-exps 精神范围内扩展语言的绝佳方式。

此外,上述解析过程可以通过“读取器宏”进行扩展,让您可以自定义编译器将文本转换为 s-exp 的方式。然而,我建议您接受 Lisp 的语法,而不是将其弯曲成其他东西。

当您提到 Lisp 的“函数式本质”和 Ruby 的“面向对象语法”时,您听起来有点困惑。我不确定“面向对象语法”应该是什么,但 Lisp 是一种多范式语言,并且它支持面向对象编程 极其地 出色地。

顺便说一句,当我说 Lisp 时,我的意思是 通用语言.

我建议你放下偏见 诚实地对待 Lisp.

括号地狱?我在以下内容中看到不再有括号:

(function toto)

比在:

function(toto);

并且在

(if tata (toto)
  (titi)
  (tutu))

不超过:

if (tata)
  toto();
else
{
  titi();
  tutu();
}

我看到的括号少,';'尽管。

你问的问题有点像问如何成为一名巧克力专家,这样你就可以从你最喜欢的巧克力蛋糕上去除所有那些地狱般的棕色东西。

是的,你可以从根本上改变语法,甚至逃离“括号地狱”。为此,您需要定义新的阅读器语法。查看阅读器宏。

然而,我确实怀疑,要达到 Lisp 专业知识水平来编写此类宏,您需要将自己沉浸在该语言中,以至于您将不再认为括号是“地狱”。IE。当你知道如何避免它们时,你就会开始接受它们是一件好事。

如果您希望 lisp 看起来像 Ruby,请使用 Ruby。

可以以非常类似 lisp 的方式使用 Ruby(和 Python),这是它们如此迅速地获得认可的主要原因之一。

请参阅以下示例,了解读取器宏如何使用 XML 模板等复杂任务来扩展 Lisp 读取器:

http://common-lisp.net/project/cl-quasi-quote/present-class.html

用户库 在编译时将 XML 的静态部分编译为 UTF-8 编码的文字字节数组,准备好按顺序写入网络流中。它们可以在普通的 lisp 宏中使用,它们是正交的......逗号字符的位置会影响哪些部分是常量以及哪些部分应在运行时评估。

更多详细信息请访问: http://common-lisp.net/project/cl-quasi-quote/

另一个用于 Common Lisp 语法扩展的项目: http://common-lisp.net/project/cl-syntax-sugar/

@sparkes

有时,LISP 是明确的语言选择,即 Emacs 扩展。我确信如果我愿意,我可以使用 Ruby 来扩展 Emacs,但 Emacs 被设计为使用 LISP 进行扩展,因此在这种情况下使用它似乎是有意义的。

这是一个棘手的问题。由于 lisp 在结构上已经非常接近解析树,因此大量宏与在解析器生成器中实现您自己的迷你语言之间的区别不是很清楚。但是,除了开始和结束括号之外,您很容易得到看起来一点也不像 lisp 的东西。

令我震惊的宏的用途之一是针对 DB 的 SQL 请求的编译时验证。

一旦您意识到您在编译时拥有完整的语言,它就会打开有趣的新视角。这也意味着您可能会以有趣的新方式搬起石头砸自己的脚(例如渲染编译不可重现,这很容易变成调试噩梦)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top