Scalaz - 结合List和State Monad进行理解

时间:2012-12-11 00:01:44

标签: scala monads scalaz monad-transformers scalaz7

我计划在我的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略有不同。

1 个答案:

答案 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类型的内容。