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

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

问题描述

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

<前>(断言(= 3(+ 1 2)))(def even? (fn [n] (= 0 (bit-and n 1))))(断言(甚至?4))(断言(=假(偶数?5)))

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

我已经查看了 Clojure 宏系统——我最熟悉的 Lisp——但这似乎太复杂了,我找不到可以轻松应用的其他线索(Clojure 宏最终编译为字节码,它不会不适用于 javascript,我也无法理解 macroexpand1 函数.)

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

补充说明:我还没有实现 quote (') 因为我无法弄清楚返回列表中应该包含什么样的值.它应该包含 AST 元素还是像 SymbolKeyword 之类的对象(后者是 Clojure 的情况)?

解决方案

宏所做的只是将未计算的形式作为参数并对其主体进行替换.实现宏系统的技巧是告诉你的编译器 lazy.

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

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

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

和一个宏:

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

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

CL-USER>(print-3-f (兰特))* 234* 234* 234CL-用户>(print-3-m (rand))* 24* 642* 85

要理解为什么会这样,从某种意义上说,您需要在头脑中运行编译器.

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

另一方面,当 Lisp 遇到这个宏时,它会将形式 (rand) untouched 传递给主体,它返回一个引用列表,其中 x(rand) 替换,产生:

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

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

此处您会找到大量关于各种语言(包括 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天全站免登陆