谓词的副作用是什么?为什么它们不好?
What are side-effects in predicates and why are they bad?
我想知道什么被认为是 fn
的谓词的副作用,例如 remove
或 filter
。似乎有多种可能性。显然,如果谓词写入文件,这是一个副作用。但是考虑这样的情况:
(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...
的引用这一事实也会改变系统的状态,因为大变量不能被垃圾收集。这也算副作用吗?
就我而言,我想在谓词中写入日志系统。这是副作用吗?
为什么完全不鼓励谓词中的副作用?是不是因为 filter
和 remove
以及他们的朋友懒惰地工作,以至于您无法确定何时调用谓词(以及 - 因此 - 何时发生副作用)?
在评估函数是否纯时,通常不会考虑 GC,尽管许多使函数不纯的操作都会产生 GC 效果。
记录是一种副作用,改变程序或世界中的任何状态也是如此。纯函数获取数据和 returns 数据,不修改任何其他内容。
https://softwareengineering.stackexchange.com/questions/15269/why-are-side-effects-considered-evil-in-functional-programming 涵盖了为什么在函数式语言中避免了副作用。
问题是确定何时甚至是否会在任何给定的函数调用中出现副作用。
如果您只关心相同的输入 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
仅仅打印参数是令人困惑的。如果副作用很大,事情可能会严重出错。
我想知道什么被认为是 fn
的谓词的副作用,例如 remove
或 filter
。似乎有多种可能性。显然,如果谓词写入文件,这是一个副作用。但是考虑这样的情况:
(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...
的引用这一事实也会改变系统的状态,因为大变量不能被垃圾收集。这也算副作用吗?
就我而言,我想在谓词中写入日志系统。这是副作用吗?
为什么完全不鼓励谓词中的副作用?是不是因为 filter
和 remove
以及他们的朋友懒惰地工作,以至于您无法确定何时调用谓词(以及 - 因此 - 何时发生副作用)?
在评估函数是否纯时,通常不会考虑 GC,尽管许多使函数不纯的操作都会产生 GC 效果。
记录是一种副作用,改变程序或世界中的任何状态也是如此。纯函数获取数据和 returns 数据,不修改任何其他内容。
https://softwareengineering.stackexchange.com/questions/15269/why-are-side-effects-considered-evil-in-functional-programming 涵盖了为什么在函数式语言中避免了副作用。
问题是确定何时甚至是否会在任何给定的函数调用中出现副作用。
如果您只关心相同的输入 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
仅仅打印参数是令人困惑的。如果副作用很大,事情可能会严重出错。