Lisp:宏可以递归吗? [英] Lisp: can a macro be recursive?

查看:142
本文介绍了Lisp:宏可以递归吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近开始使用Lisp进行编码,并且对宏印象最为深刻-它们允许我在编译时进行复杂的循环展开,这是我无法用我所知道的任何其他语言(例如,在保持原始结构的同时生​​成代码)优雅地完成的.

I've recently started coding in Lisp, and have already been most impressed with macros - they allowed me to do complex loop-unrolling at compile-time, something I can't do this elegantly in any other language that I know of (i.e. code-generate while keeping the original structure).

进行优化:我在同一代码中添加了类型注释(很多"fixnum").一旦添加了3个或4个,我就意识到自己做错了-这就是宏的用途,请不要重复自己...

On to optimization: I've sprinkled type annotations (lots of "the fixnum") in the same code. Once I've added 3 or 4 of them, I realized I was doing it wrong - this is what macros are for, Dont Repeat Yourself...

; whenever we want to indicate that the result of an operation 
; fits in a fixnum, we macro expand (the fixnum (...))
(defmacro fast (&rest args)
  `(the fixnum ,args))
...
(cond
  (...)
  (t (let* ((forOrange (+ (aref counts 5)
                          (fast * 2 (aref counts 6))
                          (fast * 5 (aref counts 7))
                          (fast * 10 (aref counts 8))))
            (forYellow (+ (aref counts 3)
                          (fast * 2 (aref counts 2))
                          (fast * 5 (aref counts 1))
                          (fast * 10 (aref counts 0))))

...而且确实如此:我没有在各处写很多(fixnum(...))",而只是在表达式前加上"fast"作为前缀-一切都很好.

...and indeed, this worked: instead of writing lots of "(the fixnum (...))" everywhere, I just quickly prefix the expression with "fast" - and all is well.

但是然后...

我意识到,即使这样也不应该止步:原则上,应该在评估的TOP处调用宏"fast",在这种情况下:

I realized that even this is not where things should stop: in principle, the macro "fast" should... be called at the TOP of the evaluation, in this case:

            (forYellow (fast + (aref counts 3)
                          (* 2 (aref counts 2))
                          (* 5 (aref counts 1))
                          (* 10 (aref counts 0))))

...,并且应在所有子表达式中递归植入"(fixnum(...))".

...and it should recursively "plant" "(the fixnum (...))" in all subexpressions.

可以做到吗? "defmacro"可以递归吗?

Can this be done? Can a "defmacro" be recursive?

更新:尝试执行此操作时遇到了一些非常奇怪的问题,因此我最终完成了Rord的建议-即实现一个函数,在repl中对其进行测试,然后从宏中调用它:

UPDATE: I faced some really weird problems trying to do this, so I ended up doing what Rord suggested below - i.e. implemented a function, tested it in the repl, and calling it from the macro:

(defun operation-p (x)
  (or (equal x '+) (equal x '-) (equal x '*) (equal x '/)))

(defun clone (sexpr)
  (cond
    ((listp sexpr)
     (if (null sexpr)
       ()
       (let ((hd (car sexpr))
             (tl (cdr sexpr)))
         (cond
           ((listp hd) (append (list (clone hd)) (clone tl)))
           ((operation-p hd) (list 'the 'fixnum (cons hd (clone tl))))
           (t (cons hd (clone tl)))))))
    (t sexpr)))

(defmacro fast (&rest sexpr)
  `(,@(clone sexpr)))

它在SBCL下工作正常:

And it works fine under SBCL:

$ sbcl
This is SBCL 1.0.52, an implementation of ANSI Common Lisp.
...
* (load "score4.cl")

T
* (setf a '(+ (1 2) (- 1 (+ 5 6)))
...
* (clone a)

(THE FIXNUM (+ (1 2) (THE FIXNUM (- 1 (THE FIXNUM (+ 5 6))))))

* (macroexpand '(fast + 1 2 THE FIXNUM (- 1 THE FIXNUM (+ 5 6))))

(THE FIXNUM (+ 1 2 THE FIXNUM (THE FIXNUM (- 1 THE FIXNUM (THE FIXNUM (+ 5 6))))))
T

一切正常,除了一个副作用:CMUCL可以工作,但不再编译代码:

All is well, except for one side-effect: CMUCL works, but no longer compiles the code:

; Error: (during macroexpansion)
; Error in KERNEL:%COERCE-TO-FUNCTION:  the function CLONE is undefined.

哦,好吧:-)

更新:在推荐答案

不仅会调用宏,还会在使用宏时对其进行扩展,因此在其定义中引用宏可能会造成混乱.但是您不必这样做:宏可以调用常规函数,因此您可以编写常规函数来进行递归列表处理,然后只需在宏中使用它即可.

A macro is not just called, but expanded when it is used, so referring to a macro in its own definition can get messy. But you don't have to do that: macros can call regular functions, so you can write a regular function to do the recursive list processing, and then just use that from the macro.

这篇关于Lisp:宏可以递归吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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