Option[F[ShoppingCart]] 到 F[Option[ShoppingCart]] 之间的转换
Conversion between Option[F[ShoppingCart]] to F[Option[ShoppingCart]]
我在 Scala 中有以下代数(我使用的是 Tagless Final Pattern):
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]]
的代码。我确定我可以做得更好,但我不知道如何改进。
我正在使用猫。
您正在寻找 traverse
和 sequence
。这些函数所做的是“切换”效果的顺序,因此如果 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
或者您可以将 map
和 sequence
合二为一 traverse
:
for {
_ <- ShoppingCarts[F].create(cartId)
maybeSc <- ShoppingCarts[F].find(cartId)
maybeNewSc <- maybeSc.traverse(sc => ShoppingCarts[F].add(sc, product))
} yield maybeNewSc
您可以在 cats docs 中阅读有关 sequence
和 traverse
的更多信息。
我建议您检查的另一件事是 monad transformers,因为它们使处理 F[Option[A]]
之类的嵌套 monad 堆栈变得容易得多。
我在 Scala 中有以下代数(我使用的是 Tagless Final Pattern):
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]]
的代码。我确定我可以做得更好,但我不知道如何改进。
我正在使用猫。
您正在寻找 traverse
和 sequence
。这些函数所做的是“切换”效果的顺序,因此如果 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
或者您可以将 map
和 sequence
合二为一 traverse
:
for {
_ <- ShoppingCarts[F].create(cartId)
maybeSc <- ShoppingCarts[F].find(cartId)
maybeNewSc <- maybeSc.traverse(sc => ShoppingCarts[F].add(sc, product))
} yield maybeNewSc
您可以在 cats docs 中阅读有关 sequence
和 traverse
的更多信息。
我建议您检查的另一件事是 monad transformers,因为它们使处理 F[Option[A]]
之类的嵌套 monad 堆栈变得容易得多。