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

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

问题描述

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

<上一页>(断言 (= 3 (+ 1 2)))(def even? (fn [n] (= 0 (bit-and n 1))))(断言(甚至?4))(assert (= false (even?5)))

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

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

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

补充一点:我还没有实现 quote (') 因为我无法弄清楚返回列表中应该包含什么样的值.它是否应该包含 AST 元素或对象,如 SymbolKeyword(Clojure 就是后者)?

解决方案

宏所做的只是将未计算的形式作为参数并在其主体上执行替换.实现宏系统的诀窍是告诉你的编译器是 lazy.

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

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

(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 (rand))* 234* 234* 234CL-用户>(打印 3 米(兰特))* 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天全站免登陆