gpt4 book ai didi

scala - 如何返回 EitherT 内的元组

转载 作者:行者123 更新时间:2023-12-03 03:48:48 24 4
gpt4 key购买 nike

我正在使用 Scalaz 7 的 EitherT 来构建混合 State 和\/的 for 推导式。到目前为止,一切都很好;我得到的基本上是:

State[MyStateType, MyLeftType \/ MyRightType]

这使我能够构建在 <- 左侧具有良好变量的 for 推导式。

但我不知道如何从状态操作返回元组。单个结果就很好 - 在下面的代码中,“val 理解”正是我想要发生的。

但是当我想返回一个元组时,事情就崩溃了; “val otherCommplementation”不会让我这样做

(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 是一个 monad 的证据,尽管它不是。在我的真实代码中,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 \/""")
}
}

我不相信这是一个好主意,但它可以解决问题。

最佳答案

正如我在上面的评论中指出的,问题是第二个 for 理解的脱糖版本涉及 2.10.2(和 2.10.1,但不是 2.10.0)中的过滤操作),并且如果左侧类型没有幺半群实例,则无法过滤 EitherT (或普通的旧 \/)。

在下面的示例中很容易看出为什么幺半群是必要的:

val x: String \/ Int = 1.right
val y: String \/ Int = x.filter(_ < 0)

什么是y?很明显,它必须是某种“空”String\/Int,并且由于 \/ 是右偏的,我们知道它不可能是那一边的值(value)。因此,我们需要左侧为零,而 String 的幺半群实例提供了这一点 - 它只是一个空字符串:

assert(y == "".left)

根据this answermy related question关于 for 推导式中的元组模式,您在 2.10.2 中看到的行为是正确且有意的 - 对 withFilter 的显然完全不必要的调用将保留。

您可以使用 Petr Pudlák 的答案中的解决方法,但还值得注意的是,以下无糖版本也非常清晰和简洁:

val notAnotherComprehension = comprehension.flatMap {
case (x, y) => doSomething.map((x, y, _))
}

无论如何,这或多或少是我天真地期望 for 理解去糖的结果(我是 not the only one )。

关于scala - 如何返回 EitherT 内的元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17418165/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com