为什么 filterv 的谓词需要没有副作用?

Why does filterv's predicate need to be free of side-effects?

终于学习了 Box2D(使用 cljbox2d port)。在 "hello world tests" 期间,我发现需要一个函数来检查框列表,销毁并从列表中删除超出范围的框。

我写的处理这个的基本函数是*:

(defn handle-out-of-bounds! [boxes]
  (filterv (fn [{:keys [body]}]
             (when-not (inbounds? (bc/position body))
               (bc/destroy! body)))
           boxes))

这里需要注意的是 destroy!,顾名思义,会产生副作用。

我决定检查一下 filterv 的来源,因为我从来没有真正检查过,并且注意到文档字符串有警告:

. . . pred must be free of side-effects.

为什么?filter我看出来了。它是惰性的,因此您无法保证谓词在任何给定点实际上 运行 除非您明确强制评估。 filterv 然而是对列表的严格缩减;在内部使用瞬态向量。唯一值得怀疑的是瞬变的使用,但我看不出这会产生什么影响。

实际上不在filterv的谓词中执行副作用的有效理由,还是仅仅是概念上的原因?


* 写完我才发现我的逻辑不对,这个函数实际上是坏了,但这不是重点。我也可以单独处理销毁和移除,但同样,这不是问题。

其他人之前对此感到困惑,例如在this mailing list post中看到相同的问题。

那些发表评论的人似乎也同意所讨论的说法是没有动机的。 filterv 很急切,副作用 pred 没有问题。

如果陈述有误,可能的解释是文档字符串中存在简单的复制粘贴错误。 mapvfilterv were introduced by Stuart Halloway,他们简单地复制了 mapfilter 的文档字符串,并用“向量”代替了“惰性序列”。