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

nie*_*aki 7 monads scala monad-transformers scalaz 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 "
}
Run Code Online (Sandbox Code Playgroud)

这一切都是不言自明的,并按预期工作.但是对于这种对我来说非常有用的方法,我希望能够将它与Listfor-comprehension 结合起来.这是一些(不工作)代码来显示我的意思:

val list = List(1, 2, 3)

val oneTwoThreeBis = for {
  i <- list
  mx <- adder(i)
} yield mx
Run Code Online (Sandbox Code Playgroud)

基本上我希望能够基于来自a的参数组合monad List- 运行monadic函数对其中的每个元素list并且在我去的时候积累副作用.我理解示例语法不起作用,我明白为什么它没有 - 我只是在寻找一个干净,优雅的等价物.

我很确定使用scalaz monad变换器可以实现这一点,更具体地来说,StateT但是我不确定如何使用它.

PS.我使用的是Scalaz 7.0-M3,因此语法可能与最常见的6.x略有不同.

Tra*_*own 9

我不确定我到底知道你在寻找什么,但听起来你想要更像traverse这里的东西(traverseHaskell的更通用的版本mapM):

import scalaz._, Scalaz._

def adder(i: Int) = State[String, Int](str => (str + i.toString + " ", i))

List(1, 2, 3).traverseS(adder)("start: ")._1
Run Code Online (Sandbox Code Playgroud)

这将按预期打印以下内容:

res0: String = "start: 1 2 3 "
Run Code Online (Sandbox Code Playgroud)

请注意,我正在使用traverseS(S代表的地方State)以避免写出相当混乱的类型参数,但是traverse当你想要将monadic函数映射到可遍历的东西时,它通常更有用.

StateT如果这不是你想要的,我很乐意举个例子,但这最终会让你有类型的东西List[(String, Int)].