我计划在我的Scala代码中开始使用Monadic样式,其中包括线程状态。这是一个结合3个monadic函数的简化示例(仅关注副作用)
import scalaz._
import Scalaz._
object MonadTest {
def adder(i: Int) = State[String, Int] ({str: String => (str + i.toString + " ", i) })
val oneTwoThreeMonad = for {
m1 <- adder(1)
m2 <- adder(2)
m3 <- adder(3)
} yield m3
oneTwoThreeMonad("start: ")._1 //String = "start: 1 2 3 "
}
这一切都是不言自明的,并按预期工作。但是对于这种对我来说非常有用的方法,我希望能够将它与List
结合起来进行理解。这是一些(不工作)代码来显示我的意思:
val list = List(1, 2, 3)
val oneTwoThreeBis = for {
i <- list
mx <- adder(i)
} yield mx
基本上我希望能够根据List
的参数组合monad - 在list
的每个元素上运行monadic函数,并在我去的时候积累副作用。我理解示例语法不起作用,我明白为什么它没有 - 我只是在寻找一个干净,优雅的等价物。
我很确定使用scalaz monad变换器可以实现这一点,更具体地说是使用StateT
,但我不确定如何使用它。
PS。我正在使用Scalaz 7.0-M3,因此语法可能与最常见的6.x略有不同。
答案 0 :(得分:9)
我不确定我到底知道你在寻找什么,但听起来你想要更像traverse
这里的东西(其中traverse
是Haskell {{1}的更一般版本}}):
mapM
这将按预期打印以下内容:
import scalaz._, Scalaz._
def adder(i: Int) = State[String, Int](str => (str + i.toString + " ", i))
List(1, 2, 3).traverseS(adder)("start: ")._1
请注意,我正在使用res0: String = "start: 1 2 3 "
(traverseS
代表S
),以避免写出相当混乱的类型参数,但State
更多当你想要将monadic函数映射到可遍历的东西时,通常很有用。
如果这不是您想要的,我很乐意给出一个traverse
示例,但这最终会导致您拥有StateT
类型的内容。