Ich habe eine einfache Sprache für einen ETL-Prozess mit der freien Monade implementiert. Bei der Verwendung von List
als Eingabe und Ausgabe sowohl zum Abrufen als auch zum Speichern von Daten funktioniert alles einwandfrei. Ich verwende jedoch Asynchron-Bibliotheken und die Arbeit mit Future[List]
So verwenden Sie die freie Monade mit Future [M [_]]
gemeinsamen Ein- und Definitionen
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]
Arbeit mit 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))
funktionieren nicht mit 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
}
wie erwartet, die Typ zurückgegeben von die flatMap
/map
ist falsch - ich bin nicht OpsF[Future]
bekomme aber eine 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] =>
meine aktuelle Problemumgehung ist store
akzeptieren Future[List[Record]]
und läßt die Interpreter Karte über die Future
haben, aber es fühlt sich ungeschickt. Das Problem ist nicht spezifisch für List
- z. Option
wäre auch nützlich.
Mache ich es falsch? Gibt es dafür eine Art Monodentrafo?
Dies scheint wie ein typisches Muster für einen Monade-Transformator, auf den ersten Blick scheint wie Haskell hat irgendwie ein 'FreeT', konnte es aber nicht in Scalaz oder Katzen finden. –
scalaz hat 'FreeT' seit [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-javadoc.jar /!/Index.html # scalaz.FreeT). –
Kann ich Sie auf die 47-Grad-Bibliothek mit dem treffenden Namen http://47deg.github.io/fetch/ verweisen, die bald zu einem Typ-Level-Inkubator wird? Wohlgemerkt, ich arbeite nicht für 47 Grad, aber es sieht so aus, als ob es bereits eine Lösung für vieles von dem, was Sie tun wollen, hat. – wheaties