cl:loop可以使用自定义求和函数吗?

时间:2013-09-25 14:51:45

标签: loops common-lisp

我可以为循环指定自定义求和函数(例如vector-add)吗?

我想做这样的事情:

(loop for vec in '((1 2) (3 4)) sum vec)
;=> (4 6)

3 个答案:

答案 0 :(得分:4)

这是一个有趣的问题。如果你能做到这一点会很好,但简短的回答是“不”。根据HyperSpec的6.1.3 Value Accumulation Clauses

  

sum构造形成了连续主值的累积和    每次迭代时提供的表单参数 var 是   用来积累总和;如果提供了 var ,则loop不会返回   最后的总和自动。 var 参数的绑定就像是   将with构造为适当类型的零。后续值   (包括任何必要的强制)计算就好像是通过函数   的 + 即可。如果使用into var ,则可以使用 type-spec var 提供类型参数;如果是非数字,则后果未指定   提供类型。如果没有into变量,则可选 type-spec   参数适用于保持总和的内部变量。该   默认类型依赖于实现的;但它必须是超类型   类型 数字

您的实际用例是否这么简单(循环遍历列表并计算它们的向量总和)还是更复杂?如果是这么简单,你可以用reduce做你想做的事。它看起来更像是

(reduce 'vector-add '((1 2) (3 4)))

其中vector-add是您的自定义求和函数。如果您仍需要使用loop,则可以使用reduce中的for sum = ... then ...和明确的loop获得finally (return sum)类行为。首先,定义为vector-add

(defun vector-add (x y)
  (mapcar '+ x y))

(vector-add '(1 2) '(3 4))
;=> (4 6)

我们可以做到:

(loop
   for vec in '((1 2) (3 4) (5 6))
   for sum = vec then (vector-add sum vec)
   finally (return sum))
;=> (9 12)

答案 1 :(得分:3)

您可以使用iterate库执行此操作:

(ql:quickload "iterate")

(use-package :iterate)

(defun vector-add (x y) (mapcar '+ x y))

(iter (for i in '((1 2) (3 4))) (reducing i by #'vector-add)) ; (4 6)

答案 2 :(得分:1)

除了使用带有for ... = ... then ...子句的特殊求和函数之外,另一种自定义求和的方法是使用sum ... into ...子句:

(loop for (n1 n2) in '((1 2) (3 4))
   sum n1 into s1
   sum n2 into s2
   finally (return (list s1 s2)))