簡體   English   中英

Option[F[ShoppingCart]] 到 F[Option[ShoppingCart]] 之間的轉換

[英]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構造中的代碼。 我確信我可以做得更好,但我不知道如何改進它。

我正在使用貓。

您正在尋找traversesequence 這些函數所做的是“切換”效果的順序,因此如果 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

或者您可以將mapsequence合並到一個步驟中traverse

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

您可以在cat 文檔中閱讀有關sequencetraverse的更多信息。

我建議您檢查的另一件事是monad 轉換器,因為它們使處理像F[Option[A]]這樣的嵌套 monad 堆棧變得更加容易。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM