如何实现一个Lisp宏系统? [英] How to implement a Lisp macro system?

查看:153
本文介绍了如何实现一个Lisp宏系统?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在node.js之上实现了自己的Lisp,我可以运行这样的s表达式:

 
(= 3(+ 1 2)))

(def even?(fn [n](= 0(bit和n 1))))

(even?4))
(assert(= false(even?5)))

宏 - defmacro 函数 - 但这是我被卡住的地方。我想知道如何宏系统在其他Lisps实现,但我找不到很多指针(除了)。



我看过Clojure宏系统 - 我最熟悉的Lisp,但是看起来太复杂了,我找不到我可以随时应用的其他线索(Clojure宏最终编译成字节代码,不适用于javascript,也不能理解 macroexpand1 函数。)



所以我的问题是:给定一个Lisp实现没有宏,但与AST,如何添加一个宏系统,如Clojure的宏系统?这个宏系统可以在Lisp中实现,还是需要在主机语言中实现的额外功能?



另外一个问题:我没有实现 quote '),因为我不知道返回的列表应该是什么样的值。应该包含AST元素或 Symbol 关键字(后者是Clojure的情况)吗?

解决方案

所有宏都是将未评估的形式作为参数,并在其主体上执行替换。实现宏系统的诀窍是告诉编译器延迟



换句话说,当编译器遇到一个函数时,它首先计算它的形式参数列表,得到结果并传递给函数。当编译器找到一个宏时,它将未评估的参数传递给body,然后执行body请求的任何计算,最后用这些结果替换它自己。



例如,假设你有一个函数:

 (defun print-3-f (progn(principal x)(princ x)(princ x)))

/ p>

 (defmacro print-3-m(x)`(progn(princ,x)(princ,x) )))

然后,您可以立即看到差异:

  CL-USER> (print-3-f(rand))
* 234
* 234
* 234

CL-USER> (print-3-m(rand))
* 24
* 642
* 85

要理解为什么会这样,你需要以一种方式运行编译器。



当Lisp遇到函数,它构建一个树,其中首先计算(rand),并将结果传递给该函数,该函数打印所述结果三次。



另一方面,当Lisp遇到宏时,它将(rand) ,它返回一个引用列表,其中 x 被替换为(rand),产生:

 (progn(princ(rand))(princ(rand))(princ(rand)))
/ pre>

并替换此新表单的宏调用。



在这里,您将找到大量有关各种语言(包括Lisp)的宏的文档。


I've implemented my own Lisp on top of node.js, I can run s-expressions like this:

(assert (= 3 (+ 1 2)))

(def even? (fn [n] (= 0 (bit-and n 1))))

(assert (even? 4))
(assert (= false (even? 5)))

Now I would like to add macros - the defmacro function - but this is where I'm stuck. I'm wondering how macro systems are implemented in other Lisps but I couldn't find many pointers (apart from this and this).

I've looked at the Clojure macro system - the Lisp I'm most familiar with - but that seemed too complicated and I couldn't find additional clues that I can readily apply (Clojure macros ultimately compile to byte code which doesn't apply to javascript, also I couldn't make sense of the macroexpand1 function.)

So my question is: given a Lisp implementation without macros but with an AST, how does one add a macro system like Clojure's macro system? Can this macro system be implemented in Lisp, or does it require extra features in the implementation in the host language?

One additional remark: I haven't implemented quote (') yet because I couldn't figure out what kind of values should be in the returned list. Should it contain AST elements or objects like Symbol and Keyword (the latter being the case for Clojure)?

解决方案

All a macro does is take unevaluated forms as parameters and perform replacement on its body. The trick to implementation a macro system is to tell your compiler to be lazy.

Put in another way, when the compiler encounters a function, it first evaluates its formal parameter list, yields the results and passes them to the function. When the compiler finds a macro, it passes the arguments unevaluated to the body, then performs any computation the body requests, and finally replaces itself with the result of those.

For instance, lets say you have a function:

(defun print-3-f (x) (progn (princ x) (princ x) (princ x)))

and a macro:

(defmacro print-3-m (x) `(progn (princ ,x) (princ ,x) (princ ,x)))

Then you can see the difference straight away:

CL-USER> (print-3-f (rand))
* 234
* 234
* 234

CL-USER> (print-3-m (rand))
* 24
* 642
* 85

To understand why this is, you need to, in a manner of speaking, run the compiler in your head.

When Lisp comes across the function, it builds a tree in which (rand) is first evaluated and the result passed to the function, which prints said result three times.

On the other hand, when Lisp comes across the macro, it passes the form (rand) untouched to the body, which returns a quoted list where x is replaced by (rand), yielding:

(progn (princ (rand)) (princ (rand)) (princ (rand)))

and replacing the macro call for this new form.

Here you will find vast amounts of documentation regarding macros in a variety of languages, including Lisp.

这篇关于如何实现一个Lisp宏系统?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆