[英]Conversion between Option[F[ShoppingCart]] to 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
我不太喜歡將Option[F[ShoppingCart]]
轉換為F[Option[ShoppingCart]]
的for-comprehension構造中的代碼。 我確信我可以做得更好,但我不知道如何改進它。
我正在使用貓。
您正在尋找traverse
和sequence
。 這些函數所做的是“切換”效果的順序,因此如果 G 有Applicative
的實例,它們就能夠將G[F[A]]
更改為F[G[A]]
。 Option
在 scope 中有這樣一個實例,所以你可以使用它。
traverse
需要額外的映射 function,但如果你只是想“切換”效果,那么sequence
將是 go 的方式:
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
您可以在cat 文檔中閱讀有關sequence
和traverse
的更多信息。
我建議您檢查的另一件事是monad 轉換器,因為它們使處理像F[Option[A]]
這樣的嵌套 monad 堆棧變得更加容易。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.