【问题标题】:Scalaz - combining List and State Monad in for comprehensionScalaz - 结合 List 和 State Monad 进行理解
【发布时间】:2012-12-11 00:01:44
【问题描述】:

我计划在我的 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

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

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

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

【问题讨论】:

    标签: scala monads scalaz monad-transformers scalaz7


    【解决方案1】:

    我不确定我是否完全理解您要查找的内容,但听起来您在这里想要更多类似于 traverse 的内容(其中 traverse 是 Haskell 的 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)来避免写出相当混乱的类型参数,但traverse 在您想要映射一个可遍历的东西的单子函数。

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

    【讨论】:

    • 看起来正是我想要的。但这并不能改变我迟早要学会在实践中使用状态转换器的事实;)
    • 我刚刚意识到我已经阅读了您的一个答案,其中包含对traversetraverseS 的详细描述,甚至为此称赞了您。我无法想象它是如何不和我在一起的......
    • 如果有人需要用 Cats 而不是 Scalaz 做类似的事情,请注意没有 traverseS 但我有一个使用 traverseU 的工作示例:github.com/benhutchison/gesture/blob/master/core/jvm/src/test/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-07
    • 1970-01-01
    • 2017-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多