Frage an playframework-2.0, scalaz, scala – Asynchrone Berechnung mit Validierung in Scala mit Scalaz

7

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 imgHier 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

Ja! Vielen Dank. Das eigentliche Problem besteht darin, ScalaZ nicht mit Play zu verwenden. Es ist eine allgemeinere Frage (über f ° prog), weil ich ohne Play (also nur ScalaZ) verwendet hatteIO anstattPromise. Daher hätte ich das gleiche Muster, das heißt:IO[Validation[E, A]] andy petrella
Ich habe vor, ScalaZ für meine Play-Apps zu 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 aussagekräftige Antwort zu geben. opyate

Deine Antwort

1   die antwort
4

Das Konzept, das Sie hier suchen, istMonadentransformatoren. Kurz gesagt, kompensieren MonadentransformatorenMonaden komponieren nicht indem Sie sie "stapeln" können.

Sie haben die Version von Scalaz, die Sie verwenden, nicht erwähntscalaz-seven branch, du wirst es findenValidationT. Dies kann verwendet werden, um jede zu wickelnF[Validation[E, A]] in einValidationT[F, E, A], wo in deinem FallF = Promise. Wenn Sie sich ändernf undg zurückgebenValidationTDann können Sie Ihren Code als

for {
  x ← f(a)
  y ← g(b)
} yield y

Dies gibt Ihnen eineValidationT[Promise, E, B] als Ergebnis.

OK. Großartiger Doc. Ich schaute in dieValidationT es istflatMap Methode ist in der Tat das, was ich brauche (und als Vermutung ist es das gleiche wie meine/~~> ein). Aber um es direkt zu verwenden,Promise benötigt eine TypeClass-Instanz vonMonad, was es nicht tut. Wenn ScalaZ herauskommt, werde ich es implementieren, um es verwenden zu könnenValidationT direkt. andy petrella
MMmh, schau, was ich suche !! Ok, also versuche ich es erstens mit dem Monadentransformator selbst, aus zwei Gründen, weil es der einzige Weg ist zu lernen, und zweitens, weil ich auf dem 6.0.4-Zweig bin. Und dann werde ich wahrscheinlich zum siebten übergehen und das ValidatorT überarbeiten ... Auf jeden Fall werde ich hierher zurückkehren, um mehr zu erzählen. Danke noch einmal andy petrella

Verwandte Fragen