7

我计划开始在我的 Scala 代码中使用 Monadic 样式来处理线程状态等。这是一个结合 3 个单子函数的简化示例(并且只关心副作用)

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

基本上,我希望能够根据来自 a 的参数组合 monads List- 在 的每个元素上运行 monadic 函数,list并在我进行时累积副作用。我理解示例语法不起作用,我明白为什么它不起作用 - 我只是在寻找一个干净、优雅的等价物。

我很确定可以使用 scalaz monad 转换器来实现这一点,更具体地说,StateT但我不确定如何去做。

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

4

1 回答 1

9

我不确定我是否完全理解您在寻找什么,但听起来您想要更像traverse这里的东西(traverseHaskell's 的更通用版本在哪里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 "

请注意,我使用traverseSS代表State)来避免写出相当混乱的类型参数,但traverse在您想要将一元函数映射到可遍历的东西时更普遍有用。

如果这不是您想要的,我很乐意举一个StateT例子,但这最终会导致您拥有 type 的东西List[(String, Int)]

于 2012-12-11T00:23:31.163 回答