首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否可以在lisp中将递归函数重写为宏?

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

Stack Overflow用户
提问于 2010-01-21 04:23:47
回答 2查看 957关注 0票数 4

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

代码语言:javascript
复制
(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 (递归和-我知道,有点傻,但只是个例子):

代码语言:javascript
复制
(defun Suma (lst)
  (if (cdr lst) 
      (+ (Suma (cdr lst))
         (car lst))
      (car lst)))

工作正常,但是宏:

代码语言:javascript
复制
(defmacro SumaMacro (lst)
  '(if (cdr lst)
       '(+ (prog (SUMAMACRO (cdr lst)))
           (prog (car lst)))
       '(car lst)))

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-01-21 05:40:04

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

代码语言:javascript
复制
(defmacro while (condition &body body)
  `(when ,condition ,@body (while ,condition ,@body)))

这里不好的地方是宏并不执行体,它只是构造了一段包含给定体的代码。所以,当函数中有这样的循环时,它会受到一些条件的保护,比如if,它可以防止无限循环。但是在这个宏代码中没有这样的条件--您可以看到宏展成了精确的原始形式,这意味着它正试图展开成一些无限的代码。就好像你已经写了

代码语言:javascript
复制
(defun foo (blah)
  (cons 1 (foo blah)))

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

票数 4
EN

Stack Overflow用户

发布于 2010-01-21 05:32:44

把像SUM或QUICKSORT这样的递归函数写成宏是没有意义的。另外,不,一般来说这是不可能的。宏扩展源代码。在编译时,宏只能看到源代码,而看不到调用代码时使用的真正参数。编译之后,宏就消失了,取而代之的是它生成的代码。然后使用参数调用这段代码。因此,宏不能在编译时根据仅在运行时知道的参数值进行计算。

例外情况是:当参数值在编译时/宏展开时已知时,宏可以展开为对自身的递归宏调用。但这是真正的高级宏用法,并不需要添加到其他程序员要维护的代码中。

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

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

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

代码语言:javascript
复制
(defun suma (list) 
  (if (rest list)
      (+ (suma (rest list))
         (first list))
    (first list)))

忘了宏吧。但是,如果你想了解更多关于宏的知识,那么Paul Graham的“On Lisp”一书(可供下载)是一个很好的知识来源。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2104672

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档