LISP宏可以走多远?

Translate

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

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

This question and all comments follow the "Attribution Required."

所有的回答

Translate

这是一个非常好的问题。

我认为这很细微,但绝对可以回答:

宏不会卡在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)))

看到这一页对于如何做到这一点。

来源
Translate

是的,您可以重新定义语法,以便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是编写编译器的好语言。

来源
Translate

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

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

您可能无法完全替换该语言并获得“ Ruby”语法,但您不需要它。得益于语言的灵活性,您可以随意使用一种方言,就好像您想使用“ Ruby编程风格”一样,这对您意味着什么。

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

来源
Translate

一遍又一遍,Lisp的新手想“摆脱所有括号”。它持续了几个星期。在普通的S表达式解析器之上构建严格的通用编程语法的项目无处可寻,因为程序员总是喜欢上您当前认为的“括号地狱”。这需要一点时间来适应,但不多!一旦您习惯了它,就可以真正体会到默认语法的可塑性,回到原来只有一种表达任何特定编程结构的方法的语言。

话虽这么说,Lisp是构建特定领域语言的出色基础。与XML一样好,甚至更好。

祝好运!

来源
Translate

我见过的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也是可扩展的,您可以教它有关新词法语法的知识。

来源
Translate

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

因此,当您加载源文件时,您的Lisp编译器将解析文本并生成s-exps。宏对这些进行操作。这很好用,并且是在s-exp精神内扩展语言的绝妙方法。

此外,可以通过“阅读器宏”扩展上述分析过程,该过程可让您自定义编译器将文本转换为s-exp的方式。但是,我建议您采用Lisp的语法,而不是将其屈从于其他语法。

当您提到Lisp的“功能性”和Ruby的“面向对象的语法”时,您会感到有点困惑。我不确定“面向对象的语法”应该是什么,但是Lisp是一种多范式语言,它支持面向对象的编程极端地好。

顺便说一句,当我说Lisp时,我的意思是普通口齿不清.

我建议你放下偏见,让Lisp诚实.

来源
Translate

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

(function toto)

比:

function(toto);

而在

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

不超过:

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

我看到的括号和';'少了虽然。

来源
Translate

您要问的问题有点像询问如何成为专家巧克力专家,以便您可以从自己喜欢的巧克力蛋糕中去除所有地狱般的棕色东西。

来源
HD.
Translate

是的,您可以从根本上更改语法,甚至可以转义“圆括号”。为此,您将需要定义新的阅读器语法。查看阅读器宏。

但是,我确实怀疑要达到Lisp专业知识的水平来编写此类宏,您将需要使自己沉浸在该语言中,以致您将不再考虑括号“地狱”。也就是说,当您知道如何避免使用它们时,您将开始接受它们是一件好事。

来源
Translate

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

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

来源
Translate

请参见以下示例,说明读取器宏如何通过复杂的任务(例如XML模板)扩展lisp读取器:

http://common-lisp.net/project/cl-quasi-quote/�z{rV���m�Xm

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

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

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

来源
Translate

@sparkes

有时LISP是明确的语言选择,即Emacs扩展。我敢肯定,如果需要的话,我可以使用Ruby来扩展Emacs,但是Emacs旨在通过LISP进行扩展,因此在这种情况下使用它似乎是有意义的。

来源
Translate

这是一个棘手的问题。由于lisp在结构上已经非常接近解析树,因此大量宏与在解析器生成器中实现自己的迷你语言之间的区别并不十分清楚。但是,除了打开和关闭括号外,您可能很容易以类似于lisp的内容结束文字。

来源
Translate

宏的用途之一令我大吃一惊,是针对数据库的SQL请求的编译时验证。

一旦意识到在编译时手边有完整的语言,它就会打开有趣的新视角。这也意味着您可以采用有趣的新方式(例如,无法进行可编译的渲染编译,这很容易变成调试的噩梦),使自己陷入困境。

来源