Ich schreibe eine vollständig asynchrone Bibliothek für den Zugriff auf einen Remote-Dienst (mit Play2.0), ich verwende Promise
und Validation
, um nicht blockierende Anruf zu erstellen, der einen Typ hat, der fehlschlägt und gültiges Ergebnis sofort.Async-Berechnung mit Validierung in Scala mit Scalaz
Promise
kommt von Play2-scala, wo Validation
von scalaz kommt.
Also 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 möchte, dass sie komponieren , Kann ich einfach die Tatsache verwenden, dass Promise
eine flatMap
präsentieren, so kann ich es mit einem Verständnis für die
for (
x <- f(a);
y <- g(b)
) yield y
01 tun
Ok, ich habe hier eine Abkürzung zu meinem Problem genommen, weil ich die Validation
Ergebnisse innerhalb des Verständnisses nicht wiederverwendet habe. Also, wenn ich x
in g
wiederverwendet werden soll, ist hier, wie ich genug
for (
x <- f(a); // x is a Validation
y <- x.fold(
fail => Promise.pure(x),
ok => g(ok)
)
) yield y
Messe tun könnte, aber diese Art von vorformulierten wird meinen Code über verschmutzen und immer wieder gehen. Das Problem hier ist, dass ich eine Art zweistufige Monadische Struktur wie M[N[_]]
habe.
In diesem Stadium gibt es eine Struktur in f ° Programmierung, die leicht die secong Ebene durch Überspringen mit einer solchen Struktur arbeiten ermöglicht:
for (
x <- f(a); //x is a B
y <- g(b)
) yield y
nun unten ist, wie ich etwas Ähnliches erreicht.
Ich habe Art von monadische Struktur, die auf zwei Ebenen in einem Wraps, lassen ValidationPromised
sagen, die die Promise
Typ mit zwei Methoden gepimpt:
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
)
}
Das bin ich solche Dinge
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
)
)
)
tun können
Wie wir sehen können /~~>
ist ziemlich ähnlich zu flatMap
aber überspringt eine Ebene. Das Problem ist die Ausführlichkeit (deshalb gibt es "For-Comprehension" in Scala und "Do" in Haskell).
Ein weiterer Punkt, habe ich die /~>
, die auch wie ein map
steht, sondern arbeitet auf der zweiten Ebene (anstelle des gültigen Typ - dritte Ebene)
So ist meine zweite Frage ist logische Folge der früheren ... stimme ich mit dieser Konstruktion einer nachhaltigen Lösung zu?
traurig sein, dass lange
Ich wollte ScalaZ jetzt schon eine Weile mit meinen Play-Apps verwenden, und das ist ein guter Anstoß für mich. Ich werde Sie wissen lassen, wie es mir geht, und ich werde hoffentlich in der Lage sein, hier eine sinnvolle Antwort zu geben. – opyate
Ja! Danke. Eigentlich liegt das eigentliche Problem nicht in der Verwendung von ScalaZ mit Play. Es ist eine allgemeinere Frage (über f ° prog), denn ohne Play (also nur ScalaZ) hätte ich 'IO' anstelle von' Promise' verwendet. Daher würde ich das gleiche Muster haben, das heißt: 'IO [Validation [E, A]]' –