私はScalaz 7のEitherTを使ってStateと\ /をブレンドするfor-comprehensionsを構築しています。ここまでは順調ですね;私は基本的に何かを得る:EitherT内でタプルを返す方法
State[MyStateType, MyLeftType \/ MyRightType]
をし、それは私がのために、内包<の左側にある素敵な変数を持って構築することができます - 。
しかし、私は状態アクションからタプルを返す方法を理解できません。単一の結果はうまくいきます - 下のコードでは、 "価値の理解"はまさに私が起こりたいものです。
しかし、タプルを返すときに物事が崩れます。 「ヴァルotherComprehensionは、」私はそれがモノイドする/ \の左側を期待して、私はその理由を理解していないように見えます
(a, b) <- comprehension
やらせません。私は何が欠けていますか?
(Scalaz 7 2.0.0-SNAPSHOT、スカラ座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 \/""")
}
}
私はこれは確信していません良いアイデアだが、それは問題を解決している。
途中で何か不思議なことが起こっています。2.10.1+デューキュアでは、ここでは、[この質問](http://stackoverflow.com/q/17424763/334519)を参照してください。同じ問題。 –
そして、明らかに、これは、 'EitherT'(または' \/')をフィルタリングするために左側のモノイドインスタンスが必要で、何らかの理由で2.10.2がこの' for'-comprehensionにフィルタ演算を張っているために起こります。 –