Option[F[ShoppingCart]]到F[Option[ShoppingCart]]之间的转换



我在Scala中有以下代数(我使用无标签最终模式):

trait ShoppingCarts[F[_]] {
def create(id: String): F[Unit]
def find(id: String): F[Option[ShoppingCart]]
def add(sc: ShoppingCart, product: Product): F[ShoppingCart]
}
使用上面的代数,我创建了以下程序:
def createAndToCart[F[_] : Monad : ShoppingCarts](product: Product, cartId: String): F[Option[ShoppingCart]] =
for {
_ <- ShoppingCarts[F].create(cartId)
maybeSc <- ShoppingCarts[F].find(cartId)
maybeNewScF = maybeSc.map(sc => ShoppingCarts[F].add(sc, product))
maybeNewSc <- maybeNewScF match {
case Some(d) => d.map(s1 => Option.apply(s1))
case _ => Monad[F].pure(Option.empty[ShoppingCart])
}
} yield maybeNewSc

我不太喜欢for-comprehension结构中的代码,它将Option[F[ShoppingCart]]转换为F[Option[ShoppingCart]]。我确信我能做得更好,但我不知道如何改进。

我用的是Cats

您正在寻找traversesequence。这些函数的作用是"切换"。所以如果G有一个Applicative的实例,他们就可以将G[F[A]]更改为F[G[A]]Option在作用域中有这样一个实例,所以您可以使用它。

traverse具有额外的映射功能,但如果您只想"切换"效果,所以sequence将走的路:

for {
_ <- ShoppingCarts[F].create(cartId)
maybeSc <- ShoppingCarts[F].find(cartId)
maybeNewSc <- maybeSc.map(sc => ShoppingCarts[F].add(sc, product)).sequence //here you need to use sequence
} yield maybeNewSc

或者您可以将mapsequencetraverse合并为一个步骤:

for {
_ <- ShoppingCarts[F].create(cartId)
maybeSc <- ShoppingCarts[F].find(cartId)
maybeNewSc <- maybeSc.traverse(sc => ShoppingCarts[F].add(sc, product))
} yield maybeNewSc

有关sequencetraverse的更多信息,请参阅cats docs。

我建议你检查的另一件事是monad转换器,因为它们使处理嵌套的monad堆栈如F[Option[A]]容易得多。

相关内容

  • 没有找到相关文章

最新更新