Recursion 是否可以在lisp中将递归函数重写为宏?

Recursion 是否可以在lisp中将递归函数重写为宏?,recursion,lisp,common-lisp,Recursion,Lisp,Common Lisp,我编写了这个快速排序函数: (defun quicksort (lst) (if (null lst) nil (let ((div (car lst)) (tail (cdr lst))) (append (quicksort (remove-if-not (lambda (x) (< x div)) tail)) (list div) (quicksor

我编写了这个快速排序函数:

(defun quicksort (lst)
  (if (null lst)
      nil
      (let ((div  (car lst))
            (tail (cdr lst)))
        (append (quicksort (remove-if-not (lambda (x) (< x div)) tail))
                (list div)
                (quicksort (remove-if     (lambda (x) (< x div)) tail))))))
工作正常,但宏:

(defmacro SumaMacro (lst)
  '(if (cdr lst)
       '(+ (prog (SUMAMACRO (cdr lst)))
           (prog (car lst)))
       '(car lst)))

似乎是错的。有人对将递归函数重写为宏有什么建议吗?

将SUM或QUICKSORT等递归函数编写为宏是没有意义的。另外,不,一般来说这是不可能的。宏扩展源代码。在编译时,宏只看到源代码,而看不到调用代码的实际参数。编译后,宏将消失,并替换为它生成的代码。然后,使用参数调用此代码。因此,宏不能在编译时根据只有在运行时才知道的参数值进行计算

例外情况是:当参数值在编译时/宏扩展时已知时,则宏可以扩展为对自身的递归宏调用。但这是真正高级的宏用法,没有任何东西可以添加到代码中供其他程序员维护

经验法则:如果你想做递归计算,那么就使用函数。如果要处理源代码,请使用宏

另外,尝试使用类似Lisp的格式。编辑器对括号进行计数、高亮显示和缩进。不要在他们自己的台词上加括号,他们在那里感到孤独。通常的Lisp样式更紧凑,并且更多地使用水平空间。如果您使用列表,则使用FIRST和REST,而不是CAR和CDR

您的“suma”函数如下所示:

(defun suma (list) 
  (if (rest list)
      (+ (suma (rest list))
         (first list))
    (first list)))

忘掉宏吧。但是,如果您想了解有关宏的更多信息,那么Paul Graham的书(可下载)是一个很好的知识来源。

您将宏和运行时混合在一起;或者换句话说,您正在混合值和语法。下面是一个非常简单的示例:

(defmacro while (condition &body body)
  `(when ,condition ,@body (while ,condition ,@body)))
这里的缺点是宏不执行主体,它只是构造一段包含给定主体的代码。因此,当函数中存在这种循环时,它会受到一些条件的保护,比如
if
,这将阻止无限循环。但是在这个宏代码中没有这样的条件——你可以看到宏扩展成了精确的原始形式,这意味着它试图扩展成一些无限的代码。就好像你写过一样

(defun foo (blah)
  (cons 1 (foo blah)))

然后将生成器函数连接到编译器中。因此,要执行这些类型的运行时循环,必须使用实函数。(需要时,您可以使用
标签
创建一个本地函数来执行递归工作。)

抱歉,但我冒昧地将asker的代码格式化为标准Lisp样式。我认为最好让它看起来像是看到区别一样。;-)有点吹毛求疵:在你的第一段中,不应该是“宏扩展时间”而不是“编译时间”?没错。我在写作时曾简要地考虑过这一点,但不想深入到细节。我想告诉大家编译可能在不同的环境中,例如另一个运行Lisp的环境,程序可能在不同的环境/Lisp会话中运行。因此,没有办法查找变量的任何运行时值。但是,您是对的,在解释器或其他宏可能被扩展的情况下也会发生同样的情况。
(defun foo (blah)
  (cons 1 (foo blah)))