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

Я пытаюсь определить абстрактную алгебру, которая позволит мне отложить выбор того, какую монаду я буду использовать, чтобы обернуть эффективную операцию (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 и не имеет конструктора.

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

trait MyAlg[F: cats.Monad]

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

Можно ли написать мою filterValidElements функцию, оставив isValid abstract и F generic?

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

1 Ответ

0 голосов
/ 05 сентября 2018

Попробуйте добавить неявные параметры, указывающие, что вы можете сделать 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
        })
}
...