我是 Clojure / 使用不可变值编程的函数式方法的忠实粉丝。
但是我不确定延迟是否应该被视为一个不可变的值(假设你延迟一个纯函数)。我对较大的不可变数据结构中存在一个或多个延迟的情况特别感兴趣。
例如包含延迟的向量:
[1 2 (delay (reduce + (range 1000)))]
据我所见,这表现得好像它是一个不可变的值,因为在您强制其评估之前您看不到延迟的结果 - 然后结果被缓存,之后该值永远不会改变。
以这种方式将延迟视为不可变值有什么问题吗?
我是 Clojure / 使用不可变值编程的函数式方法的忠实粉丝。
但是我不确定延迟是否应该被视为一个不可变的值(假设你延迟一个纯函数)。我对较大的不可变数据结构中存在一个或多个延迟的情况特别感兴趣。
例如包含延迟的向量:
[1 2 (delay (reduce + (range 1000)))]
据我所见,这表现得好像它是一个不可变的值,因为在您强制其评估之前您看不到延迟的结果 - 然后结果被缓存,之后该值永远不会改变。
以这种方式将延迟视为不可变值有什么问题吗?
延迟模拟通常称为thunk的东西,它是对尚未评估的表达式的引用,一旦被强制,它就会被其结果替换,并且此后是不可变的。Haskell 使用这种内部可变的 thunk 来模拟非严格评估。该表达式[1, 2, foldl1 (+) [0..1000]]
名义上与其在具有严格评估的语言中的显式延迟等效项相同。
当然,如果延迟对象中使用的函数是纯函数,则将其视为不可变也没有什么坏处。您可以通过以下几种方式来考虑这一点:
根据定义,纯函数可以用其结果替换。
局部突变(在这种情况下是延迟对象)不会使函数不纯。
当然,Clojure 不区分纯函数和不纯函数,因此作为开发人员,您需要认真对待它。
delay
是一个“价值生产者”,就像一个函数是一个价值生产者,只是delay
让“价值生产者代码”懒惰地执行,即当它被要求提供价值时,而不变性是正在产生的价值的属性因此,可以将生成的值视为不可变的,就像函数调用一样。这是关于产生的价值,但如果你的功能正在产生副作用,那么你可能会遇到其他问题,但产生的价值仍然是不可变的