【发布时间】:2020-04-19 20:16:24
【问题描述】:
在函数式编程的最充分指南Chapter 8 中,他们定义了一个新类IO,其定义如下:
class IO {
static of(x) {
return new IO(() => x);
}
constructor(fn) {
this.$value = fn;
}
map(fn) {
return new IO(compose(fn, this.$value));
}
inspect() {
return `IO(${inspect(this.$value)})`;
}
}
作者解释:
IO通过在函数包装器中捕获不纯操作来延迟它。作为 这样,我们认为IO包含被包装的返回值 动作而不是包装器本身。这在 功能:我们有一个IO(x),IO(() => x)只是为了避免 评估。
但我对.of() 方法如何延迟评估感到困惑。例如,从节的开头开始定义,
// getFromStorage :: String -> (_ -> String)
const getFromStorage = key => () => localStorage[key];
如果我尝试创建一个新的IO 对象,例如IO.of(localStorage[42]),这根本不会延迟评估。 localStorage[42] 的值将立即计算(假设计算为 "foo"),然后将使用 { $value: () => "foo" } 创建新的 IO 对象。
我了解像new IO(key => () => localStorage[key]) 这样直接 调用构造函数如何延迟评估,但我不明白作者使用.of() 方法的含义以及如何“避免评估” .另外,作者在IO的任何示例中都没有使用.of(),而是直接调用构造函数。
【问题讨论】:
-
For monads
of表示将纯值放入相应 monad 的上下文中,在这种情况下为IO(更好的是Defer)。这意味着没有什么可以推迟了。当您将其放入上下文时,该值已被评估。这样做仍然是明智的,因为您现在可以在IOmonad 中使用这个纯值。 -
@bob 嗯,这很有道理。那么作者所说的“这在
of函数中很明显:我们有一个IO(x),IO(() => x)只是为了避免评估所必需的”是什么意思。我们不再避免使用这个纯值进行评估,因为正如你所说,它已经被评估了。 -
我认为Brian 只是试图提出另一点,即我们不应该将
IO视为一个无效函数。在这个特定的点上,要遵循他的想法有点困难。 -
这实际上是一个很好的例子,为什么我们需要
of作为 monad API 的一部分,而不仅仅是相应的构造函数。它们可能会有所不同,例如IO。
标签: javascript functional-programming monads