functional repository-build get()基于find()/create()方法

a6b3iqyw  于 2021-07-14  发布在  Java
关注(0)|答案(1)|浏览(238)

我有这样的代数

object Algebra {
  case class Product(id: String, description: String)
  case class ShoppingCart(id: String, products: List[Product])

  trait ShoppingCarts[F[_]] {
    def create(id: String): F[Unit]
    def get(id: String): F[ShoppingCart]
    def find(id: String): F[Option[ShoppingCart]]
  }
}

我提出了以下实现。但我想知道是否有可能在trait本身中实现它作为泛型方法。我试图将上下文绑定到函子以访问Map,但这不是有效的构造。

override def get(id: String): ScRepoState[ShoppingCart] =
  find(id).flatMap {
    case Some(sc) => sc.pure[ScRepoState]
    case None => create(id) *> get(id)
  }

另一个问题是实现addmany()metdhod。我有这样的东西

def addMany[F[_] : Monad](cartId: String, products: List[Product])(implicit shoppingCarts: ShoppingCarts[F]): F[ShoppingCart] = {
    for {
      cart    <- shoppingCarts.get(cartId)
      product <- products.pure[F]
      newCart <- product.traverse(product => shoppingCarts.add(cart, product))
    } yield newCart
  }

我挣扎着如何在一个理解块中混合不同的 Package

jq6vz3qz

jq6vz3qz1#

但我想知道是否有可能在trait本身中实现它作为泛型方法。
不完全是。Scala2不允许traits有参数,但是可以使用抽象类。您既可以不完全使用trait,也可以使用一个包含所有可派生实现的默认类,例如:

abstract class DefaultShoppingCarts[F[_]: Monad] extends ShoppingCarts[F] {
  override def get(id: String): F[ShoppingCart] =
    find(id).flatMap {
      case Some(sc) => sc.pure[F]
      case None     => create(id) >> get(id)
    }
}

这是我比较喜欢的方法,但也有其他直接改变特征的方法。
您可以添加 Monad 方法的参数:

trait ShoppingCarts[F[_]] {
  def create(id: String): F[Unit]
  def find(id: String): F[Option[ShoppingCart]]
  def get(id: String)(implicit F: Monad[F]): F[ShoppingCart] =
    find(id).flatMap {
      case Some(sc) => sc.pure[F]
      case None     => create(id) >> get(id)
    }
}

这与我们在抽象类示例b/c的使用站点中所做的非常不同 ShoppingCarts 将被迫使用monad而不是构建站点,并且实现者如果想要重写该方法,就必须完全复制签名,即使这样做 Monad[F] 未使用。
您还可以模拟trait参数对抽象隐式def的作用:

trait ShoppingCarts[F[_]] {
    implicit protected def F: Monad[F]
    def create(id: String): F[Unit]
    def get(id: String): F[ShoppingCart] =
      find(id).flatMap {
        case Some(sc) => sc.pure[F]
        case None     => create(id) >> get(id)
      }
    def find(id: String): F[Option[ShoppingCart]]
  }

这是可行的,但是在实现 F 成员。
我挣扎着如何在一个理解块中混合不同的 Package
你没有。不允许混合。不要用它来理解列表,只能用它来理解 F . 在一些更复杂的情况下,您可能需要嵌套以获得理解,或者使用monad转换器,但是这里您只需要在f中工作。我也不知道什么是回报类型的 add ,但假设是 F[ShoppingCart] :

def addMany[F[_] : Monad](cartId: String, products: List[Product])(implicit shoppingCarts: ShoppingCarts[F]): F[ShoppingCart] = {
    for {
      cart    <- shoppingCarts.get(cartId)
      results <- products.traverse(product => shoppingCarts.add(cart, product))
      // results is a list of intermediate carts, get the last one; fallback if list was empty
    } yield results.lastOption.getOrElse(cart)
  }

下一次请单独问第二个问题。

相关问题