Recursion Clojure中的递归循环通过宏抛出错误
我一直在尝试用clojure编写一个递归循环,它将打印出列表中的最后一个数字。重点不是我需要得到最后一个数字(我确信有一个内置的函数用于此),而是我想更好地理解clojure中的递归和宏。所以我有这个宏Recursion Clojure中的递归循环通过宏抛出错误,recursion,clojure,macros,Recursion,Clojure,Macros,我一直在尝试用clojure编写一个递归循环,它将打印出列表中的最后一个数字。重点不是我需要得到最后一个数字(我确信有一个内置的函数用于此),而是我想更好地理解clojure中的递归和宏。所以我有这个宏 (defmacro loop-do [the-list] `(if (= (count '~the-list) 1) (println (first '~the-list)) (loop-do (rest '~the-list)))) 但是我得到了一个堆栈溢出错
(defmacro loop-do [the-list]
`(if (= (count '~the-list) 1)
(println (first '~the-list))
(loop-do (rest '~the-list))))
但是我得到了一个堆栈溢出错误。我做错了什么?人们将如何使用你的宏?
在某个地方,有人会打电话:
(loop-do list)
作为一段代码,这些只是列表中的两个符号。第一个被识别为您的宏,第二个,list
,是表示将在运行时绑定的变量的符号。但您的宏只知道这是一个符号
这同样适用于:
(loop-do (compute-something))
参数是一个表单,但您不希望获取该表单的最后一个元素,而只获取在计算代码后获得的列表的最后一个元素
因此:您只知道在宏中,列表将绑定到一个表达式,在运行时,该表达式必须是一个列表。您不能将列表
当作一个列表来使用:无论是(count'list)
还是(count'(compute something))
都不能满足您的需要
您可以扩展到(计数列表)
或(计数(计算某物))
,但结果只能在运行时计算。宏的工作只是生成代码
递归宏
宏不是递归的:它们扩展为递归调用
可能会扩展为:
(let [a0 a] (if a0 a0 (and b c)))
宏扩展过程是一个应该终止的固定点,但宏不会调用自身(这意味着什么,在定义宏时是否会扩展代码?)。“展开为递归调用”中的“递归”宏应该有一个基本情况,即它不会展开为自身(独立于运行时会发生什么或不会发生什么)
。。。将替换为:
(loop-do (rest 'x))
。。。这将再次扩大。
这就是为什么评论说大小实际上在增长,这就是为什么会出现stackoverflow错误:macroexpansion从未找到固定点
调试宏
您有一个堆栈溢出错误。如何调试它
使用,它只执行一次宏扩展:
(macroexpand-1 '(loop-do x))
=> (if (clojure.core/= (clojure.core/count (quote x)) 1)
(clojure.core/println (clojure.core/first (quote x)))
(user/loop-do (clojure.core/rest (quote x))))
您可以看到生成的代码仍然包含对
usr/loop do
的调用,但参数是(clojure.core/rest(quote x))
。这就是您应该寻找的症状。看看循环/重现函数。在这一行:(循环执行(rest'~列表))
您将以下列表按字面意思传递给宏:(rest…
,这样您就不会在每一步上减小数据大小。相反,您放大了列表),但rest如何放大列表?我想,如果我传递(123445)
,它只会返回除第一个元素之外的所有元素,并将其传递到循环do
?我确信这有一个内置函数:是的,它会放大一个leetwinski,因为当您以(循环do(rest'~列表))的方式调用宏时,您正在将未计算符号的列表((rest'~列表)
)传递回宏<代码>(rest'~列表)
在被赋予宏之前不会被计算。如果您想实践宏,您应该尝试执行实际需要宏的任务。试着重写核心宏。啊,我明白了!这是非常清楚的!谢谢你简洁而详细的解释!:)
(loop-do (rest 'x))
(macroexpand-1 '(loop-do x))
=> (if (clojure.core/= (clojure.core/count (quote x)) 1)
(clojure.core/println (clojure.core/first (quote x)))
(user/loop-do (clojure.core/rest (quote x))))