Macros LISP宏能走多远?

Macros LISP宏能走多远?,macros,lisp,Macros,Lisp,我读过很多关于LISP可以动态地重新定义语法的文章,大概是关于宏的。我很好奇这到底能走多远?您能否重新定义语言结构,使其成为另一种语言的编译器?例如,您能否将LISP的功能性质改为更面向对象的语法和语义,比如说让语法更接近Ruby 特别是,是否可以使用宏摆脱括号地狱?我已经学会了足够多的(Emacs-)LISP,可以用我自己的微功能自定义Emacs,但我很好奇宏在自定义语言方面能走多远。如果你想让LISP看起来像Ruby,请使用Ruby 以类似lisp的方式使用Ruby(和Python)是可能的

我读过很多关于LISP可以动态地重新定义语法的文章,大概是关于宏的。我很好奇这到底能走多远?您能否重新定义语言结构,使其成为另一种语言的编译器?例如,您能否将LISP的功能性质改为更面向对象的语法和语义,比如说让语法更接近Ruby


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

如果你想让LISP看起来像Ruby,请使用Ruby

以类似lisp的方式使用Ruby(和Python)是可能的,这也是他们如此迅速地被接受的主要原因之一。

@sparkes


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

这是一个棘手的问题。由于lisp在结构上已经非常接近解析树,因此大量宏与在解析器生成器中实现自己的迷你语言之间的区别并不十分清楚。但是,除了开始和结束参数外,您很容易得到一个与lisp完全不同的结果。

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

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

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

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

顺便说一句,我说的是口齿不清


我建议你抛开你的偏见。

我不是一个Lisp专家,见鬼,我甚至不是一个Lisp程序员,但在对该语言进行了一点实验后,我得出结论,过了一段时间,括号开始变得“不可见”,你开始看到你想要的代码。您开始更多地关注通过s-expr和宏创建的语法结构,而较少关注列表和括号文本的词汇形式

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

您可能无法完全替换该语言并获得“Ruby”语法,但您不需要它。多亏了语言的灵活性,如果你愿意,你最终可能会有一种方言,让你觉得你是在遵循“Ruby风格的编程”,不管这对你意味着什么


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

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


然而,我确实怀疑,为了达到LISP专长来编程这样的宏,你需要把自己沉浸在语言中,这样你就不会再考虑这些“地狱”了。也就是说,当你知道如何避免它们时,你就会把它们当作一件好事来接受。

这是一个非常好的问题

我认为这是微妙的,但肯定是可以回答的:

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

例如:

(loop for x from 0 below 100
      when (even x)
      collect x)
也就是说,大多数简单的宏只使用s表达式。你会被“卡住”使用它们

但s-表达式,就像塞尔吉奥回答的那样,开始感觉正确。语法不再碍事,您开始在语法树中编码

对于reader宏,是的,您可以编写如下内容:

#R{
      ruby.code.goes.here
  }
但您需要编写自己的Ruby语法解析器

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

#B(some lisp (code goes here))
会转化为

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

有关如何操作,请参见。

括号地狱?我看不到以下括号:

(function toto)
比在:

function(toto);
而且

(if tata (toto)
  (titi)
  (tutu))
不超过:

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

我看到更少的括号和“;”但是。

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

Common Lisp具有内置功能,可为读取器和读取器宏定义新语法以处理该语法。此处理在读取时完成(在编译或评估时之前)。要了解有关在Common Lisp中定义读取器宏的更多信息,请参阅Common Lisp Hyperspec——您需要阅读并使用它。(我相信该计划也有相同的功能,但我对它不太熟悉——请参阅)

作为一个简单的例子,假设您希望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,{像a(而}像a)。然后创建一个函数