Фильтруйте F[List[Int]], используя Int => F[Boolean], где F - универсальный

Я пытаюсь определить абстрактную алгебру, которая позволит мне отложить выбор того, какую монаду я буду использовать для переноса эффективной операции (IO, Task, Future и т. Д.) До запуска программы.

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

Представьте, что мне нужно сделать что-то, возможно, побочные эффекты в isValidвроде проверить дб.

Что было бы хорошо, если бы я мог уйти isValid а также getElements абстрактный --- так что, например, одна реализация может подключаться к базе данных, а другая может ссылаться на макет для тестирования ---, но определить общий 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 и не имеет конструктора.

Конечно, я не могу установить Explicity F быть монадой, например как

trait MyAlg[F: cats.Monad]

потому что черты не могут иметь параметры типа с контекстными границами.

Есть ли способ написать мой filterValidElements функция, оставляя isValid абстрактный и F общий?

Я довольно новичок в этом стиле, так что, возможно, я поступаю совершенно неправильно.

1 ответ

Решение

Попробуйте добавить неявные параметры, указывающие, что вы можете сделать map (т.е. Functor) а также pure ака point (т.е. InvariantMonoidal). Например, вы можете сделать это Applicative или же Monad,

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
        })
}
Другие вопросы по тегам