我需要编写一个程序,它可以评估某些变量范围内的总和,如:
(sum-range (i 2 N) (sin i))
一般来说:
(sum-range (iteration-variable begin end) my-body
为此:
同样的产品。我不能使用任何循环/迭代构造,只为自己编写一个,使用尾递归。
我需要用宏来完成它,但无法了解这些事情。我没有要求提供完整的代码,只需要对宏和用法进行一些解释。首先,如何将变量(iteration-variable
)传递给sin
?如何在宏内部实现尾递归?
据我所知,宏创建了一些列表,它被替换为调用点并在那里进行求值。我对吗?所以我的解决方案是为2到N之间的每个i创建sin i
列表,然后为此列表创建apply
+`。可以吗?
答案 0 :(得分:4)
首先,你应该看看你想写什么,然后,它应该扩展到什么代码。
宏将输入 forms (代码)作为参数并对其进行转换。因此,参数列表需要具有您想要编写的结构。
在你的情况下,你想写
(sum-range (iteration-variable begin end) #|my-body|#)
其中my-body
是一些用变量计算内容的形式。您可以将其指定为单个表单,但有时在这样的主体中进行任意计算很方便,因此我将允许下面的一般情况。
您的参数列表需要反映出来(我使用var
代替iteration-variable
):
(defmacro sum-range ((var begin end) &body body)
#|how to sum body with var...|#)
现在,如果没有宏,你需要写什么?你循环遍历范围,用var来评估body的评估。幸运的是,对于这种解释,这很好地转换为loop
构造。
(loop :for var :from begin :to end
:sum #|what to sum with var...|#)
因此宏需要产生这样的形式。我们有非常好的代码模板语法(quasiquote),可以让我们很好地表达:
(defmacro sum-range ((var begin end) &body body)
`(loop :for ,var :from ,begin :to ,end
:sum (progn ,@body)))
(progn
允许正文中有多个表单,返回最后一个表单的值。)
这与编写
大致相同(defmacro sum-range ((var begin end) &body body)
(list 'loop :for var :from begin :to end
:sum (list* 'progn body)))
现在,当你写
(sum-range (i 2 n)
(sin i))
它将宏扩展到
(loop :for i :from 2 :to n
:sum (progn
(sin i)))
您现在的任务是使用尾递归函数替换loop
解决方案。您应该首先定义递归函数,然后使用宏将代码转换为该函数的调用。将正文传递给该函数可以通过将其包装在lambda
(匿名函数)中来完成。