使用Int => F [Boolean]过滤F [List [Int]],其中F是通用的

问题描述 投票:1回答:1

我正在尝试定义一个抽象代数,这将允许我推迟选择我将用于包装有效操作(IO,任务,未来等)的Monad直到我运行程序。

trait MyAlg[F[_]]
  def isValid(v: int): F[Boolean]
  def getElements(): F[List[Int]]
  def filterValidElements(vs: F[List[Int]]): F[List[Int]]

想象一下,我需要在isValid中做一些可能产生副作用的事情,比如检查数据库。

如果我可以留下isValidgetElements摘要,那将是更好的例子,以便例如一个实现可以连接到数据库而另一个可以引用模拟测试---但是定义一个通用的filterValidElements所以我不需要为两种情况重新赋予相同的功能。像这样的东西:

def filterValidElements(es: F[List[Int]]]): F[List[Int]] = 
      es.map(
        elems => elems.map(
          e => (e, isValid(e))).collect{
            case (e, F(true)) => e
       })

但是,F是通用的,因此它不提供map并且没有构造函数。

当然,我不能明确地将F设置为Monad,例如

trait MyAlg[F: cats.Monad]

因为traits不能具有带上下文边界的类型参数。

有没有办法写我的filterValidElements函数,留下isValid摘要和F通用?

我对这种风格很陌生,所以我可能会以完全错误的方式解决这个问题。

scala generic-programming scala-cats
1个回答
2
投票

尝试添加隐式参数,指定您可以执行map(即Functor)和pure aka point(即InvariantMonoidal)。例如,你可以使它成为ApplicativeMonad

import cats.{Functor, InvariantMonoidal}
import cats.syntax.functor._
import scala.language.higherKinds

trait MyAlg[F[_]] {
  def isValid(v: Int): F[Boolean]
  def getElements(): F[List[Int]]
  def filterValidElements(es: F[List[Int]])(implicit functor: Functor[F], im: InvariantMonoidal[F]): F[List[Int]] =
    es.map(
      elems => elems.map(
        e => (e, isValid(e))).collect{
          case (e, fb) if fb == im.point(true) => e
        })
}
© www.soinside.com 2019 - 2024. All rights reserved.