Ich gebe zu, dass der Titel nicht sehr explizit ist: Entschuldigung dafür.Scalaz: Validierung in einem Verständnis und Logging
Angenommen, ich habe einen für Verständnis:
for {v1<-Validation1(input)
v2<-Validation2(v1)
v3<-Validation3(v2)
} yield result
Validation1, Validation2 und Validation3 einiger Kontrollen zu tun (zum Beispiel "Alter> 18") und die Verwendung scheitern/Erfolg; Wenn also etwas nicht stimmt, bricht das Verständnis ab und ich bekomme den Grund für den fehlgeschlagenen Teil des Ergebnisses, sonst bekomme ich den erwarteten Wert im Erfolgsteil. So weit, so gut und nichts sehr schwer.
Aber Validation1, Validation2, Validation3 sind erfolgreich, wenn ihre Eingabe einige Regeln erfüllt (z. B .: "Der Typ kann wählen, weil sein Alter größer als 18 ist und seine Nationalität Französisch ist"). Was ich möchte, ist, die Regeln zu verfolgen, die angewendet werden, um sie am Ende anzeigen zu können.
Es ist eindeutig ein Anwendungsfall der Protokollierung. aber ich zögere, auf dem Weg, es zu tun:
Haben Sie ein Objekt „Logger“, die von jeder Funktion (Validation1, 2 und 3, sondern auch den Anrufer, der den Inhalt des Protokolls anzuzeigen will) zugänglich ist
der Logger Stellen ein Parameter Validation1, 2 und 3
Warten Sie auf die betreffenden Kapitel von "Funktionale Programmierung in Scala" :)
Andere? > 1/sqrt (x)
Zuerst - x: Also, ich nehme an, die Funktion berechnet werden soll
Vielen Dank für Ihre Ratschläge
auf 10
April Bearbeitet Ich berechne sqrt (x), indem ich überprüfe, dass x> 0 und dann nehme ich die inverse wenn nicht null.
mit scalaz.Validation, es ist ganz einfach:
val failsquareroot= "Can't take squareroot of negative number"
val successsquareroot= "Squareroot ok"
val failinverse="Can't take inverse of zero"
val successinverse= "Inverse ok"
def squareroot(x:Double)=if (x < 0) failsquareroot.fail else sqrt(x).success
def inverse(x:Double)= if (x == 0) failinverse.fail else (1/x).success
def resultat(x:Double)= for {
y <- squareroot(x)
z<-inverse(y)
} yield z
Wenn nun squareroot Erfolge, ich möchte die Zeichenfolge successsquaretoot protokollieren und wenn inverse sucesses, möchte ich die Zeichenfolge successinverse anmelden, so dass die Funktion resultat akkumuliert die beide Strings im Erfolgsfall
ich mit ValidationT begann als Yo Acht vorgeschlagen:
def squareroot2(x:Double)=ValidationT[({type f[x] = Writer[String,x]})#f, String,Double](Writer(successsquareroot,squareroot(x)))
def inverse2(x:Double)=ValidationT[({type f[x] = Writer[String,x]})#f, String,Double](Writer(successinverse,inverse(x)))
Aber ich kann nicht h finden um sie zum Verständnis zu kombinieren. Um das Ergebnis von einem von ihnen zu erhalten, muss ich schreiben: squareroot2 (4) .run.laufen die seltsam scheint und in der Art, wie ich schrieb es, auch im Falle des Scheiterns wird die Saiten successsquareroot protokolliert:
println(squareroot2(-1).run.run)
druckt: (SquareRoot ok, Failure (kann nicht squareroot negative Zahl nehmen))
Vielen Dank! Benoit
Herausgegeben am 12. April
So Yo Acht vorgeschlagen, diesen Auszug:
def squareroot(x:Double) = if (x < 0) failureT("Can't take squareroot of negative number") else successT(sqrt(x))
def inverse(x:Double) = if (x == 0) failureT("Can't take inverse of zero ") else successT(1/x)
for {
y <- squareroot(x).flatMapF(i => Writer("Squareroot ok", i))
z <- inverse(y).flatMapF(i => Writer("Inverse ok", i))
} yield z
und er warnte mich, dass einige Typenannotationen notwendig war. Effektiv ist die Rückgabe von Quadratwurzel und Inverse ziemlich hässlich: Es ist eine Validierung von etwas, das ich schwer zu verstehen hatte!
Also, ich musste den Rückgabetyp explizit angeben: def inverse (x: Double): ValidierungT [?, E, A] wo "E" ist String und "A" ist Double (das war einfach!). Aber was ist mit dem ersten? Es muss eine Monade sein (soweit ich das verstehe) und ich wählte das Einfachste: Id (das ist Identität).
So, jetzt haben wir:
def squareroot(x:Double):ValidationT[Id,String,Double]=if (x < 0) failureT(failsquareroot) else successT(sqrt(x))
def inverse(x:Double):ValidationT[Id,String,Double]=if (x == 0) failureT(failinverse)else successT(1/x)
Aber die für Verständnis nicht kompilieren, weil "y" kein Double ist aber ein WriterT [Id, String, Double] Darüber hinaus ist die erste Nachricht protokolliert ("Quadratwurzel ok") ist "verloren".
Schließlich habe ich wie folgt aus:
0 : Failure(Can't take inverse of zero)
-1 : Failure(Can't take squareroot of negative number)
4 : Success((Squareroot ok, Inverse ok,0.5)
abkühle
def resultat(x:Double) = for {
y <- squareroot(x).flatMapF(i => Writer("Squareroot ok", i))
z <- inverse(y.run._2).flatMapF(i => Writer(y.run._1 + ", Inverse ok", i))
} yield z.run //Note that writing "z.run.run" doesn't compile
println("0 : " + resultat(0.0).run)
println("-1 : " +resultat(-1.0).run)
println("4 : " + resultat(4).run)
die gibt! Ich wäre besser, eine Liste [String] für den Schriftsteller zu verwenden, aber ich denke, dass ich auf dem guten Weg bin!
Und jetzt kann ich meinen Urlaub (morgen!) Denke :)
Herausgegeben am 14. Mai
gut, wird der Code nicht kompiliert werden, aber der Fehler ist in Yo Acht letzten Vorschlag (Beachten Sie, dass es nicht ein Verstoß ist wieder Yo Acht, die ein Modell der Freundlichkeit ist!). Ich gebe Ihnen den vollständigen Code und den Fehler:
import scala.math._
import scalaz._
import Scalaz._
object validlog extends ValidationTFunctions {
val failsquareroot= "Can't take squareroot of negative number"
val successsquareroot= "Squareroot ok"
val failinverse="Can't take inverse of zero"
val successinverse= "Inverse ok"
case class MyId[A](v: A)
implicit val myIdPointed = new Pointed[MyId]{
def point[A](v: => A) = MyId(v)
}
implicit def unId[A](my: MyId[A]): A = my.v
def squareroot(x:Double):ValidationT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double]=if (x < 0) failureT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double](failsquareroot) else successT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double](sqrt(x))
def inverse(x:Double):ValidationT[({type f[x] = WriterT[MyId, String, x]})#f,String,Double]=if (x == 0) failureT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double](failinverse) else successT[({type f[x] = WriterT[MyId,String, x]})#f,String,Double](1/x)
/* def resultat(x:Double) = for {
y <- squareroot(x).flatMapF(i => Writer(", Squareroot ok", i))
z <- inverse(y).flatMapF(i => Writer(", Inverse ok", i))
} yield z */
def main(args: Array[String]): Unit = {
println(inverse(0.0).run)
println(inverse(0.5).run)
println(squareroot(-1.0).run)
println(inverse(4.0).run)
}
}
Hier ist die Sitzung des Terminal:
[email protected]:~$ cd scala
[email protected]:~/scala$ scala -version
Scala code runner version 2.9.2 -- Copyright 2002-2011, LAMP/EPFL
[email protected]:~/scala$ scala -cp ./scalaz7/scalaz-core_2.9.2-7.0-SNAPSHOT.jar validlog.scala
/home/benoit/scala/validlog.scala:15: error: object creation impossible, since method map in trait Functor of type [A, B](fa: Main.MyId[A])(f: A => B)Main.MyId[B] is not defined
implicit val myIdPointed = new Pointed[MyId]{
^
one error found
Ich denke, es ist etwas, das ich von Anfang verpasst haben, die erklären könnte, warum ich bin für einige Wochen geklebt!
Benoit
Herausgegeben am 15. Mai
Ihren Code kompilieren, habe ich einen ersten Fehler:
could not find implicit value for parameter F: scalaz.Pointed[Main.$anon.ValidationTExample.WriterAlias]
Nach einigen Versuchen habe ich den Import auf diese Weise neu geschrieben:
import scalaz.Writer
import scalaz.std.string._
import scalaz.Id._
import scalaz.WriterT
import scalaz.ValidationT
import scala.Math._
Es gibt Sti ll einen Fehler:
error: could not find implicit value for parameter F: scalaz.Monad[[x]scalaz.WriterT[[+X]X,String,x]]
y <- squareroot(x).flatMapF(i => Writer("Squareroot ok", i))
^
one error found
Dieser Fehler war mit dem Code, den Sie am 14. Mai Offensichtlich schrieben, ist es schwierig zu verstehen, was genau IImport mit scalaz-seven. Mit der Version 6 sahen die Dinge einfacher aus: man musste nur scalaz._ und Scalaz._
Ich fühle mich wie ein "verzweifelt Hausschreiber" :) (Ja, ich stimme zu, es ist nicht sehr klug, aber es ist entspannend!)
Benoit
23. Mai
Ouf! Es funktioniert effektiv mit der letzten Version von scalaz-seven: Beachten Sie, dass ich es erstellen musste, anstatt einen Snapshot herunterzuladen.
das ist großartig!
Für diejenigen, die interessiert sind, hier ist die Ausgabe:
0 : (Squareroot ok,Failure(Can't take inverse of zero))
-1 : (,Failure(Can't take squareroot of negative number))
4 : (Squareroot ok, Inverse ok,Success(0.5))
Yo Acht, wenn zufällig wir eines Tages treffen, ich werde Sie ein Bier bezahlen!
Benoit
Ich denke, Ihre Version von Scalaz-sieben ist nicht gut. Der Code läuft korrekt mit der letzten Version von Scalaz-sieben Zweig –
Ich habe Ihren Beitrag verpasst. Das ist, was ich vermutete. Ich benutze den Schnappschuss vom 14. April. Ich hätte Zeit, heute Abend mit der letzten Version zu testen. – bhericher