Scalaz 为有状态计算提供了一个很好的抽象:ST monad。
ST monad 允许以函数形式捕获副作用计算。
我想,在 Haskell 中,使用这样的 monad 是有效实现某些命令式算法的唯一方法。
但在 Scala 中,如有必要,我可以简单地使用可变数据结构。
我发现,使用 Scalaz 的函数概念会带来计算开销。参见例如 this question .因此,如果期望的目标是提高效率,那么使用 ST monad 从功能实现切换到功能实现似乎是不合理的。
我要问的是:
请您参考如下方法:
正如 Don Stewart 正确指出的那样,您似乎在寻找 ST monad 而不是 state monad。所以我的回答将是关于这个的。
ST monad 用于在 Haskell 中允许本地可变性,通常不允许可变性。例如,如果你想写一个命令式 sum函数,你会使用 ST monad。带有 scalaz 的此类函数的示例是(取自 here ):
def sumST[S, A](as: List[A])(implicit A: Numeric[A]): ST[S, A] =
for { n <- newVar(A.zero)
_ <- as.traverseU(a => n.mod(A.plus(_, a)))
m <- n.read } yield m
def sum[A : Numeric](as: List[A]): A =
runST(new Forall[({type λ[S] = ST[S, A]})#λ] {
def apply[S] = sumST[S, A](as)
})
显然在 Scala 中我们也可以这样写:
def sum[A](xs: List[A])(implicit N: Numeric[A]) = {
var sum = N.zero
val it = xs.iterator
while (it.hasNext) {
sum = N.plus(sum, it.next)
}
sum
}
这仍然是引用透明的,因为没有可变状态超出函数的范围。在 Haskell 中,它用于这些情况,因为我们根本不能有
var .
那么我们为什么要在scala中使用ST呢?如果您想处理可变结构(如数组)并想保证该可变结构不会超出计算范围,而是必须先变成不可变结构,则可以使用 ST。在 scalaz 你有
STArray 对于这种情况,这将变成
ImmutableArray当 ST monad 正在运行时。一个很好的例子是
binary sort example in scalaz .值得一读的还有
blog article on ST monad来自 Rúnar Bjarnason。




