Asynchrone Berechnung mit Validierung in Scala mit Scalaz
Ich schreibe gerade eine vollständig asynchrone Bibliothek, um auf einen Remote-Dienst zuzugreifen (mit Play2.0)Promise
undValidation
um einen nicht blockierenden Anruf zu erstellen, der einen Fehlertyp und ein gültiges Ergebnis auf einmal aufweist.
Promise
kommt von Play2-Scala, woValidation
kommt von scalaz.
Hier ist die Art von Beispielen für solche Funktionen
f ::A => Promise[Validation[E, B]]
g ::B => Promise[Validation[E, C]]
So weit, so gut, jetzt, wenn ich sie komponieren möchte, kann ich einfach die Tatsache nutzen, dassPromise
präsentieren aflatMap
, damit ich es mit einem for-verständnis machen kann
for (
x <- f(a);
y <- g(b)
) yield y
Ok, ich habe hier eine Abkürzung zu meinem Problem genommen, weil ich die nicht wiederverwendet habeValidation
Ergebnisse im Rahmen des Vorverständnisses. Also wenn ich wiederverwenden willx
img
Hier ist, wie ich tun könnte
for (
x <- f(a); // x is a Validation
y <- x.fold(
fail => Promise.pure(x),
ok => g(ok)
)
) yield y
Fair genug, aber diese Art von Boilerplate wird meinen Code immer und immer wieder verschmutzen. Das Problem dabei ist, dass ich eine Art zweistufige monadische Struktur habeM[N[_]]
.
In dieser Phase gibt es eine Struktur in der f ° -Programmierung, die es ermöglicht, mit einer solchen Struktur zu arbeiten, indem die zweite Ebene leicht übersprungen wird:
for (
x <- f(a); //x is a B
y <- g(b)
) yield y
Im Folgenden erfahren Sie, wie ich etwas Ähnliches erreicht habe.
Ich habe eine Art monadische Struktur geschaffen, die die beiden Ebenen in einer zusammenfasstValidationPromised
die pimpte diePromise
Schreibe mit zwei Methoden:
def /~> [EE >: E, B](f: Validation[E, A] => ValidationPromised[EE, B]): ValidationPromised[EE, B] =
promised flatMap { valid =>
f(valid).promised
}
def /~~>[EE >: E, B](f: A => ValidationPromised[EE, B]): ValidationPromised[EE, B] =
promised flatMap { valid =>
valid.fold (
bad => Promise.pure(KO(bad)),
good => f(good).promised
)
}
Dies ermöglicht mir, solche Dinge zu tun
endPoint.service /~~> //get the service
(svc => //the service
svc.start /~~> (st => //get the starting elt
svc.create(None) /~~> //svc creates a new elt
(newE => //the created one
newEntry.link(st, newE) /~~> //link start and the new
(lnk => Promise.pure(OK((st, lnk, newE)))) //returns a triple => hackish
)
)
)
Wie wir sehen können/~~>
ist ziemlich ähnlich zuflatMap
überspringt aber eine Ebene. Das Problem ist die Ausführlichkeit (deshalb gibt es in Scala "zum Verständnis" und in Haskell "zu tun").
Ein weiterer Punkt, ich habe die/~>
das steht wie einmap
funktioniert aber auch auf der zweiten Ebene (anstelle des gültigen Typs -dritte Niveau)
Meine zweite Frage ist also eine Folge der ersteren ... Nähere ich mich mit dieser Konstruktion einer nachhaltigen Lösung?
Es tut mir leid, so lange zu sein