LISP宏可以走多远?

Mik*_*one 45 lisp macros

我已经阅读了很多内容,LISP可以动态地重新定义语法,大概是宏.我好奇这到底有多远?你能重新定义语言结构,以至于它的边界成为另一种语言的编译器吗?例如,您是否可以将LISP的功能性质更改为更面向对象的语法和语义,或许可以说语法更接近像Ruby这样的东西?

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

Eri*_*and 34

这是一个非常好的问题.

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

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

例:

(loop for x from 0 below 100
      when (even x)
      collect x)
Run Code Online (Sandbox Code Playgroud)

话虽这么说,大多数简单的宏只使用s表达式.你会被"困住"使用它们.

但像塞尔吉奥所回答的那样,s表达开始感觉正确.语法不受影响,您可以在语法树中开始编码.

对于读者宏,是的,你可以想象写这样的东西:

#R{
      ruby.code.goes.here
  }
Run Code Online (Sandbox Code Playgroud)

但是你需要编写自己的Ruby语法解析器.

您还可以使用编译为现有Lisp构造的宏来模仿某些Ruby构造(如块).

#B(some lisp (code goes here))
Run Code Online (Sandbox Code Playgroud)

会翻译成

(lambda () (some lisp (code goes here)))
Run Code Online (Sandbox Code Playgroud)

请参阅此页面了解如何操作.

  • 循环宏示例是s-expr,但"子表达式"不是. (12认同)
  • @Kaz 但不知何故没有发生,答案也很棒:) (2认同)

Sea*_*son 22

是的,您可以重新定义语法,以便Lisp成为编译器.您可以使用"Reader Macros"执行此操作,这与您可能正在考虑的常规"编译器宏"不同.

Common Lisp具有内置工具,可以为读取器和读取器宏定义新语法来处理该语法.此处理在读取时间(在编译或eval时间之前)完成.要了解有关在Common Lisp中定义阅读器宏的更多信息,请参阅Common Lisp Hyperspec - 您将要阅读Ch.2,"语法"Ch.23,"读者".(我认为方案具有相同的设施,但我不熟悉它-看到计划来源电弧的编程语言).

举个简单的例子,让我们假设您希望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 #\( #\[ )
Run Code Online (Sandbox Code Playgroud)

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

您可以执行的其他操作包括,例如,创建新的字符串语法或使用[和]括起in-fix表示法并将其处理为S表达式.

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


Ser*_*sta 16

我不是Lisp专家,哎呀我甚至不是Lisp程序员,但经过一些语言实验后,我得出的结论是,一段时间后,括号开始变为'隐形',你开始看到代码为你想要它.您开始更多地关注通过s-exprs和宏创建的语法结构,而不是注意列表和括号文本的词法形式.

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

您可能无法完全替换语言并获得"Ruby"语法,但您不需要它.由于语言的灵活性,你可以找到一种方言,感觉就像你想要遵循'Ruby风格的编程'一样,无论那对你意味着什么.

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


jfm*_*fm3 15

一遍又一遍,Lisp的新手想要"摆脱所有的括号".它持续数周.没有任何项目可以在通常的S表达式解析器之上构建一个严格的通用编程语法,因为程序员总是最喜欢你当前认为的"括号地狱".它需要一点点习惯,但不是很多!一旦你习惯了它,你就可以真正体会到默认语法的可塑性,回到只有一种表达任何特定编程结构的方式的语言真的很光.

话虽这么说,Lisp是构建领域特定语言的绝佳基础.和XML一样好,如果不是更好的话.

祝好运!

  • 如果语法可能是您认为适合表达手头程序的任何内容,该怎么办? (2认同)

Dan*_*reb 12

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

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

从大约55分钟开始.这是"实用公共Lisp"的作者Peter Seibel给出的一个视频,这是最好的Lisp教科书.

Lisp宏的动机通常难以解释,因为它们真的是在一个冗长的情况下出现在一个简单的教程中.彼得提出了一个很好的榜样; 你可以完全掌握它,它可以很好地正确使用Lisp宏.

你问:"你能否将LISP的功能性改变为更面向对象的语法和语义".答案是肯定的.事实上,Lisp最初根本没有任何面向对象的编程,因为Lisp在面向对象编程之前就已存在,所以并不奇怪!但是当我们在1978年第一次了解OOP时,我们能够轻松地将它添加到Lisp中,其中包括宏.最终开发了Common Lisp对象系统(CLOS),这是一个非常强大的面向对象编程系统,可以很好地适应Lisp.整个东西可以作为扩展加载 - 没有任何内置!这一切都是用宏完成的.

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


Luí*_*ira 11

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

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

此外,上述解析过程可以通过"读取器宏"进行扩展,使您可以自定义编译器将文本转换为s-exps的方式.但是,我建议您接受Lisp的语法,而不是将其弯曲成其他内容.

当你提到Lisp的"功能性"和Ruby的"面向对象语法"时,你听起来有点困惑.我不确定应该是什么"面向对象的语法",但Lisp是一种多范式语言,它极其支持面向对象的编程.

顺便说一下,当我说Lisp时,我指的是Common Lisp.

我建议你放弃偏见,给Lisp一个诚实的去.


小智 10

括号地狱?我看到没有更多的括号:

(function toto)
Run Code Online (Sandbox Code Playgroud)

比在:

function(toto);
Run Code Online (Sandbox Code Playgroud)

并在

(if tata (toto)
  (titi)
  (tutu))
Run Code Online (Sandbox Code Playgroud)

不超过:

if (tata)
  toto();
else
{
  titi();
  tutu();
}
Run Code Online (Sandbox Code Playgroud)

我看到更少的括号和';' 虽然.


小智 9

你问的有点像问如何成为一个专家巧克力制作者,以便你可以从你最喜欢的巧克力蛋糕中删除所有那些地狱般的褐色东西.


HD.*_*HD. 6

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

但我确实怀疑要达到Lisp专业知识的水平来编程这样的宏,你需要让自己沉浸在语言中,以至于你不再考虑括号"地狱".即当你知道如何避免它们时,你会接受它们作为一件好事.