gpt4 book ai didi

Scala Cat 使用 Ior 累积错误和成功

转载 作者:行者123 更新时间:2023-12-01 07:39:48 28 4
gpt4 key购买 nike

我正在尝试使用 Cats 数据类型 Ior 来累积使用服务的错误和成功(可能返回错误)。

def find(key: String): F[Ior[NonEmptyList[Error], A]] = {
(for {
b <- service.findByKey(key)
} yield b.rightIor[NonEmptyList[Error]])
.recover {
case e: Error => Ior.leftNel(AnotherError)
}
}

def findMultiple(keys: List[String]): F[Ior[NonEmptyList[Error], List[A]]] = {
keys map find reduce (_ |+| _)
}

我的困惑在于如何组合错误/成功。我正在尝试使用 Semigroup combine(中缀语法)进行组合但没有成功。有一个更好的方法吗?任何帮助都会很棒。

最佳答案

我将假设您想要所有错误和所有成功结果。这是一个可能的实现:

class Foo[F[_]: Applicative, A](find: String => F[IorNel[Error, A]]) {
def findMultiple(keys: List[String]): F[IorNel[Error, List[A]]] = {
keys.map(find).sequence.map { nelsList =>
nelsList.map(nel => nel.map(List(_)))
.reduceOption(_ |+| _).getOrElse(Nil.rightIor)
}
}
}

让我们分解一下:

我们将尝试“翻转”一个 List[IorNel[Error, A]]进入 IorNel[Error, List[A]] .但是,从做 keys.map(find)我们得到 List[F[IorNel[...]]] ,所以我们还需要先以类似的方式“翻转”它。这可以通过使用 .sequence 来完成结果,是什么力量 F[_]: Applicative约束。

注意 Applicative[Future]只要有隐式 ExecutionContext 就可用在适用范围。你也可以摆脱 F并使用 Future.sequence直接地。

现在,我们有 F[List[IorNel[Error, A]]] ,所以我们要 map内部改造 nelsList我们有。你可能会认为 sequence也可以在那里使用,但不能 - 它具有“第一个错误时短路”的行为,因此我们会丢失所有成功的值。让我们尝试使用 |+|反而。
Ior[X, Y]有一个 Semigroup两个 X 的实例和 Y有一个。由于我们使用的是 IorNel , X = NonEmptyList[Z] ,这就满足了。对于 Y = A - 您的域类型 - 它可能不可用。

但我们不想将所有结果合并为一个 A ,我们要 Y = List[A] (它也总是有一个半群)。所以,我们取每一个 IorNel[Error, A]我们有和 map A到单例 List[A] :
nelsList.map(nel => nel.map(List(_)))

这给了我们 List[IorNel[Error, List[A]] ,我们可以减少。不幸的是,由于 Ior 没有 Monoid ,我们不能完全使用方便的语法。因此,对于 stdlib 集合,一种方法是执行 .reduceOption(_ |+| _).getOrElse(Nil.rightIor) .

这可以通过做几件事来改善:
  • x.map(f).sequence相当于做x.traverse(f)
  • 我们可以预先要求键非空,并返回非空结果。

  • 后一步给了我们 Reducible一个集合的例子,让我们通过做 reduceMap 来缩短一切

    class Foo2[F[_]: Applicative, A](find: String => F[IorNel[Error, A]]) {
    def findMultiple(keys: NonEmptyList[String]): F[IorNel[Error, NonEmptyList[A]]] = {
    keys.traverse(find).map { nelsList =>
    nelsList.reduceMap(nel => nel.map(NonEmptyList.one))
    }
    }
    }

    当然,你可以用这个做一个单线:

    keys.traverse(find).map(_.reduceMap(_.map(NonEmptyList.one)))

    或者,您可以在内部进行非空检查:

    class Foo3[F[_]: Applicative, A](find: String => F[IorNel[Error, A]]) {
    def findMultiple(keys: List[String]): F[IorNel[Error, List[A]]] = {
    NonEmptyList.fromList(keys)
    .map(_.traverse(find).map { _.reduceMap(_.map(List(_))) })
    .getOrElse(List.empty[A].rightIor.pure[F])
    }
    }

    关于Scala Cat 使用 Ior 累积错误和成功,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59289503/

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