我正在使用Scalaz 7的EitherT來構造將狀態和\ /混合起來的理解。到現在爲止還挺好;我得到的東西,基本上就是:如何返回EitherT中的元組
State[MyStateType, MyLeftType \/ MyRightType]
和,讓我建立-內涵是對<左側漂亮的變量 - 。我想不出如何從狀態動作返回元組。單個結果就好 - 在下面的代碼中,「val理解」正是我想要發生的事情。
但是當我想返回一個元組時,事情就會崩潰; 「VAL otherComprehension」不會讓我做
(a, b) <- comprehension
它看起來像它預計\左側/是一個Monoid,我不明白爲什麼。我錯過了什麼?
(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+在這裏解釋'for'-comprehension-看到[這個問題](http://stackoverflow.com/q/17424763/334519)的簡化版同樣的問題。 –
而且很清楚,這是因爲過濾'EitherT'(或'\ /')需要左側的monoid實例,出於某種原因,2.10.2將過濾操作粘在這個'for'''理解中。 –