我正在使用 Scalaz 7 的 EitherT 来构建融合 State 和 \/. 到目前为止,一切都很好; 我得到的东西基本上是:
State[MyStateType, MyLeftType \/ MyRightType]
这使我可以构建在 <-.
但我不知道如何从状态动作中返回元组。单一的结果就好了——在下面的代码中,“val理解”正是我想要发生的。
但是当我想返回一个元组时,事情就崩溃了;“val otherComprehension”不会让我做
(a, b) <- comprehension
看起来它希望 \/ 的左侧是 Monoid,我不明白为什么。我错过了什么?
(Scalaz 7 2.0.0-SNAPSHOT,Scala 2.10.2)
object StateProblem {
case class MyStateType
case class MyRightType
case class MyLeftType
type StateWithFixedStateType[+A] = State[MyStateType, A]
type EitherTWithFailureType[F[+_], A] = EitherT[F, MyLeftType, A]
type CombinedStateAndFailure[A] = EitherTWithFailureType[StateWithFixedStateType, A]
def doSomething: CombinedStateAndFailure[MyRightType] = {
val x = State[MyStateType, MyLeftType \/ MyRightType] {
case s => (s, MyRightType().right)
}
EitherT[StateWithFixedStateType, MyLeftType, MyRightType](x)
}
val comprehension = for {
a <- doSomething
b <- doSomething
} yield (a, b)
val otherComprehension = for {
// this gets a compile error:
// could not find implicit value for parameter M: scalaz.Monoid[com.seattleglassware.StateProblem.MyLeftType]
(x, y) <- comprehension
z <- doSomething
} yield (x, y, z)
}
编辑:我已经添加了 MyLeftType 是一个单子的证据,即使它不是。在我的真实代码中,MyLeftType 是一个案例类(称为 EarlyReturn),所以我可以提供一个零,但仅当参数之一为零时,追加才有效:
implicit val partialMonoidForEarlyReturn = new Monoid[EarlyReturn] {
case object NoOp extends EarlyReturn
def zero = NoOp
def append(a: EarlyReturn, b: => EarlyReturn) =
(a, b) match {
case (NoOp, b) => b
case (a, NoOp) => a
case _ => throw new RuntimeException("""this isnt really a Monoid, I just want to use it on the left side of a \/""")
}
}
我不相信这是一个好主意,但它正在解决问题。