【问题标题】:Sum and product macros in LISPLISP 中的求和和乘积宏
【发布时间】:2014-11-05 20:02:55
【问题描述】:

我需要编写一个程序,该程序在某个变量的某个范围内计算总和,例如:

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

一般:

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

为此:

产品也是如此。我不能使用任何循环/迭代构造,只为自​​己写一个,使用尾递归

我需要用宏来完成,但不知道这些东西。我不要求完整的代码,只需要对宏和用法进行一些解释。首先,变量(iteration-variable)如何传递给sin?如何在宏中实现尾递归?

据我了解,宏创建了一些列表,该列表被替换为调用点并在那里进行评估。我对吗?所以我的解决方案是为 2 到 N 之间的每个 i 创建 sin i 列表,然后将 apply+` 加入到这个列表中。还好吗?

【问题讨论】:

  • 那么对于 (i 1 1000) 你会在一个列表中创建 1000 个 sin 调用吗?这有意义吗?

标签: macros sum lisp tail-recursion


【解决方案1】:

首先,你应该看看你想写什么,然后,它应该扩展成什么代码。

宏将输入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 允许 body 中有多个表单,返回最后一个表单的值。)

这和写作差不多

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

【讨论】:

  • 我可以在里面定义循环函数吗(使用labelslet)?
  • 是的,当然,但这意味着宏会在您使用它的每个地方扩展到该创建。我发现把它放在外面更清楚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多