LISP中的总和和产品宏

时间:2014-11-05 20:02:55

标签: macros sum lisp tail-recursion

我需要编写一个程序,它可以评估某些变量范围内的总和,如:

(sum-range (i 2 N) (sin i))

一般来说:

(sum-range (iteration-variable begin end) my-body

为此:

enter image description here

同样的产品。我不能使用任何循环/迭代构造,只为自​​己编写一个,使用尾递归

我需要用宏来完成它,但无法了解这些事情。我没有要求提供完整的代码,只需要对宏和用法进行一些解释。首先,如何将变量(iteration-variable)传递给sin?如何在宏内部实现尾递归?

据我所知,宏创建了一些列表,它被替换为调用点并在那里进行求值。我对吗?所以我的解决方案是为2到N之间的每个i创建sin i列表,然后为此列表创建apply +`。可以吗?

1 个答案:

答案 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(匿名函数)中来完成。