Я реализовал простой язык для процесса ETL, используя свободную монаду. При использовании List
в качестве входных и выходных данных для сбора и хранения данных все работает нормально. Однако я использую асинхронное библиотеки и работать с Future[List]
Как использовать свободную монаду с Future [M [_]]
общего импорта и определения
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import cats.free.Free
import cats.free.Free._
sealed trait Ops[A]
type OpsF[A] = Free[Ops, A]
работы с List
case class Fetch(offset: Int, amount: Int) extends Ops[List[Record]]
case class Store(recs: List[Record]) extends Ops[List[Response]]
def fetch(offset: Int, amount: Int): OpsF[List[Record]] =
liftF[Ops, List[Record]](Fetch(offset, amount))
def store(recs: List[Record]): OpsF[List[Response]] =
liftF[Ops, List[Response]](Store(recs))
def simpleEtl(offset: Int, amount: Int): Free[Ops, List[Response]] =
fetch(offset, amount).flatMap(r => store(r))
не работает с Future[List]
case class Fetch(offset: Int, amount: Int) extends Ops[Future[List[Record]]]
case class Store(recs: List[Record]) extends Ops[Future[List[Response]]]
def fetch(offset: Int, amount: Int): OpsF[Future[List[Record]]] =
liftF[Ops, Future[List[Record]]](Fetch(offset, amount))
def store(recs: List[Record]): OpsF[Future[List[Response]]] =
liftF[Ops, Future[List[Response]]](Store(recs))
// explicit types in case I am misunderstanding more than I think
def simpleEtl(offset: Int, amount: Int): Free[Ops, Future[List[Response]]] =
fetch(offset, amount).flatMap { rf: Future[List[Record]] =>
val getResponses: OpsF[Future[List[Response]]] = rf map { r: List[Record] =>
store(r)
}
getResponses
}
, как и ожидалось, тип, возвращаемый из flatMap
/map
неправильно - я не получаю OpsF[Future]
но Future[OpsF]
Error:(34, 60) type mismatch;
found : scala.concurrent.Future[OpsF[scala.concurrent.Future[List[Response]]]]
(which expands to) scala.concurrent.Future[cats.free.Free[Ops,scala.concurrent.Future[List[String]]]]
required: OpsF[scala.concurrent.Future[List[Response]]]
(which expands to) cats.free.Free[Ops,scala.concurrent.Future[List[String]]]
val getResponses: OpsF[Future[List[Response]]] = rf map { r: List[Record] =>
мой текущий обходной путь, чтобы иметь store
принять Future[List[Record]]
и дать карту переводчика по Future
, но он чувствует себя неуклюжим.
Вопрос не относится к List
- например. Option
было бы полезно.
Я делаю это неправильно? Для этого есть какой-то монадный трансформатор?
Это похоже на типичный образец для монадного трансформатора, на первый взгляд кажется Haskell каким-то образом «FreeT», но не смог найти его в скалясе или котах. –
У скаляза есть 'FreeT', поскольку [7.2.0] (https://oss.sonatype.org/service/local/repositories/releases/archive/org/scalaz/scalaz_2.11/7.2.0/scalaz_2.11-7.2 0,0-javadoc.jar /!/index.html # scalaz.FreeT). –
Могу ли я указать вам на библиотеку 47 градусов, точно названную http://47deg.github.io/fetch/, которая скоро станет инкубатором типа? Имейте в виду, я не работаю на 47 градусов, но похоже, что у этого уже есть решение для большей части того, что вы хотите сделать. – wheaties