谓词的副作用是什么?为什么它们不好?

What are side-effects in predicates and why are they bad?

我想知道什么被认为是 fn 的谓词的副作用,例如 removefilter。似乎有多种可能性。显然,如果谓词写入文件,这是一个副作用。但是考虑这样的情况:

(def *big-var-that-might-be-garbage-collected* ...)

(let [my-ref *big-var-that-might-be-garbage-collected*]
  (defn my-pred
    [x]
    (some-operation-on my-ref x)))

即使 some-operation-on 只是一个不改变状态的查询,my-pred 保留对 *big... 的引用这一事实也会改变系统的状态,因为大变量不能被垃圾收集。这也算副作用吗?

就我而言,我想在谓词中写入日志系统。这是副作用吗?

为什么完全不鼓励谓词中的副作用?是不是因为 filterremove 以及他们的朋友懒惰地工作,以至于您无法确定何时调用谓词(以及 - 因此 - 何时发生副作用)?

在评估函数是否纯时,通常不会考虑 GC,尽管许多使函数不纯的操作都会产生 GC 效果。

记录是一种副作用,改变程序或世界中的任何状态也是如此。纯函数获取数据和 returns 数据,不修改任何其他内容。

https://softwareengineering.stackexchange.com/questions/15269/why-are-side-effects-considered-evil-in-functional-programming 涵盖了为什么在函数式语言中避免了副作用。

I found this link helpful

问题是确定何时甚至是否会在任何给定的函数调用中出现副作用。

如果您只关心相同的输入 return 相同的答案,那很好。副作用取决于函数的执行方式

例如,

(first (filter odd? (range 20)))
; 1

但是如果我们安排 odd? 打印它的参数:

(first (filter #(do (print %) (odd? %)) (range 20)))

它会在返回1之前打印012345678910111213141516171819

原因是 filter 在可能的情况下在 32 个元素的 chunks 中处理其序列参数。

如果我们取消 range 的限制:

(first (filter #(do (print %) (odd? %)) (range)))

...我们打印了一个全尺寸块:012345678910111213141516171819012345678910111213141516171819202122232425262728293031

仅仅打印参数是令人困惑的。如果副作用很大,事情可能会严重出错。