Scalaz对有状态计算提供了一个很好的抽象:ST monad。
ST monad允许以函数形式捕获副作用计算。
在Haskell中,我想,使用这样的monad是有效实现某些命令式算法的唯一方法。
但是在Scala中,如果需要,我可以简单地使用可变数据结构。
我发现,使用Scalaz的功能概念带来了计算开销。请参阅示例this question。因此,如果期望的目标是提高效率,使用ST monad从功能实现切换到功能实现似乎是不合理的。
我要问的是:
答案 0 :(得分:11)
正如Don Stewart正确指出的那样,你似乎在寻找ST monad而不是州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
,当ST monad运行时,它将变为ImmutableArray
。一个很好的例子就是binary sort example in scalaz。值得一读的还有RúnarBjarnason的blog article on ST monad。