我写了这个快速排序函数:
(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))))))但是我不能将它重写为宏,它不能工作,也不能,例如,这个简单的foo (递归和-我知道,有点傻,但只是个例子):
(defun Suma (lst)
(if (cdr lst)
(+ (Suma (cdr lst))
(car lst))
(car lst)))工作正常,但是宏:
(defmacro SumaMacro (lst)
'(if (cdr lst)
'(+ (prog (SUMAMACRO (cdr lst)))
(prog (car lst)))
'(car lst)))似乎是错的。有人对将递归函数重写为宏有什么建议吗?
发布于 2010-01-21 05:40:04
您混合了宏和运行时;或者换句话说,您混合了值和语法。下面是一个非常简单的例子:
(defmacro while (condition &body body)
`(when ,condition ,@body (while ,condition ,@body)))这里不好的地方是宏并不执行体,它只是构造了一段包含给定体的代码。所以,当函数中有这样的循环时,它会受到一些条件的保护,比如if,它可以防止无限循环。但是在这个宏代码中没有这样的条件--您可以看到宏展成了精确的原始形式,这意味着它正试图展开成一些无限的代码。就好像你已经写了
(defun foo (blah)
(cons 1 (foo blah)))然后将生成器函数挂接到编译器中。所以要做这些类型的运行时循环,你必须使用一个实数函数。(当需要时,您可以使用labels创建一个本地函数来执行递归工作。)
发布于 2010-01-21 05:32:44
把像SUM或QUICKSORT这样的递归函数写成宏是没有意义的。另外,不,一般来说这是不可能的。宏扩展源代码。在编译时,宏只能看到源代码,而看不到调用代码时使用的真正参数。编译之后,宏就消失了,取而代之的是它生成的代码。然后使用参数调用这段代码。因此,宏不能在编译时根据仅在运行时知道的参数值进行计算。
例外情况是:当参数值在编译时/宏展开时已知时,宏可以展开为对自身的递归宏调用。但这是真正的高级宏用法,并不需要添加到其他程序员要维护的代码中。
经验法则:如果你想做递归计算,那就使用函数。如果你想处理源代码,那就使用宏。
另外,尝试使用类似Lisp的格式。编辑器对括号进行计数,并进行高亮显示和缩排。不要把括号放在他们自己的行上,他们在那里会感到孤独。通常的Lisp风格更紧凑,也更多地使用水平空间。如果你使用列表,那么使用FIRST和REST,而不是CAR和CDR。
您的“suma”函数将如下所示:
(defun suma (list)
(if (rest list)
(+ (suma (rest list))
(first list))
(first list)))忘了宏吧。但是,如果你想了解更多关于宏的知识,那么Paul Graham的“On Lisp”一书(可供下载)是一个很好的知识来源。
https://stackoverflow.com/questions/2104672
复制相似问题