Przyznaję, że tytuł nie jest zbyt jednoznaczny: przepraszam za to.Scalaz: sprawdzanie poprawności w zrozumieniu i rejestrowaniu
Załóżmy Mam do-zrozumienia:
for {v1<-Validation1(input)
v2<-Validation2(v1)
v3<-Validation3(v2)
} yield result
Validation1, Validation2 i Validation3 zrobić kilka kontroli (np "wiek> 18") i wykorzystania fail/sukces; więc jeśli coś jest nie tak, to zrozumienie przerywane i dostaję przyczynę w części porażki wyniku, w przeciwnym razie otrzymam oczekiwaną wartość w części dotyczącej sukcesu. Jak dotąd, tak dobrze i nic bardzo trudnego.
Ale sprawdzanie poprawności1, sprawdzanie poprawności2, sprawdzanie poprawności3 zakończyły się pomyślnie, jeśli ich dane wejściowe spełniają pewne reguły (np. "Facet może głosować, ponieważ jego wiek jest większy niż 18, a narodowość to francuski"). to, czego chcę, to śledzenie reguł, które są stosowane, aby móc je wyświetlić na końcu.
Jest to wyraźnie przypadek użycia logowania. ale waham się na drodze, aby to zrobić:
Czy obiekt „rejestratora”, który jest dostępny przez dowolną funkcję (Validation1, 2 i 3, ale również osoby dzwoniącej, który chce wyświetlać zawartość dziennika)
Wykorzystaj rejestrator parametrem Validation1, 2 i 3
Poczekaj na odnośnym rozdziale "programowanie funkcyjne w Scala" :)
nawzajem?
Dziękuję za rady
Zmieniano 10 kwietnia
Więc załóżmy, że chcę, aby obliczyć funkcję: x -> 1/sqrt (x)
pierwszy, Obliczam sqrt (x), sprawdzając, że x> 0, a następnie przyjmuję odwrotność, jeśli nie jest zero.
z scalaz.Validation, to jest proste:
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
Teraz, jeśli SquareRoot sukcesy, chcę zalogować się successsquaretoot ciąg i jeśli odwrotnych sucesses, chcę zalogować się successinverse ciąg tak, że funkcja Resultat gromadzi oba ciągi w przypadku powodzenia
zacząłem ValidationT jak Yo Osiem zasugerował:
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)))
Ale nie mogę znaleźć h łącząc je w celu zrozumienia. Ponadto, aby uzyskać wynik jednego z nich, muszę napisać: squareroot2 (4) .run.uruchomić co wydaje się dziwne iw sposób pisałem, nawet w razie awarii successsquareroot struny jest logowanie:
println(squareroot2(-1).run.run)
nadrukami: (SquareRoot ok, Failure (Nie można wziąć SquareRoot z liczby ujemnej))
Dziękujemy! Benoit
Edited 12 kwietnia
Więc Yo Osiem zaproponował ten fragment:
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
i ostrzegł mnie, że niektóre adnotacje typu była konieczna. Efektywnie, powrót trojga pierwiastków kwadratowych i odwrotnych jest raczej brzydki: jest to walidacja czegoś, co trudno mi zrozumieć!
Musiałem więc wyraźnie określić typ zwrotu: def inverse (x: Double): ValidationT [?, E, A], gdzie "E" to String, a "A" Double (to było łatwe!). Ale co z pierwszym? Musi to być monada (o ile rozumiem) i wybrałem prostszą: Id (Tożsamość).
Więc teraz mamy:
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)
Ale za-pojmowania nie kompiluje bo "y" nie jest podwójny, ale WriterT [Id, String, Double] Ponadto pierwszy zalogowanych wiadomość ("Squareroot ok") jest "zagubiony".
Ostatecznie zrobiłem tak:
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)
co daje:
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)
Cool! Byłoby mi lepiej użyć List [String] dla Writera, ale myślę, że jestem na dobrej drodze!
A teraz mogę myśleć do moich wakacji (jutro!) :)
Zmieniano 14 maja
dobrze, kod nie kompiluje, ale błąd jest w Yo Osiem Zeszły sugestia (zauważ, że to nie jest obraza ponownie Yo Eight, który jest wzorem życzliwości!). Przesłać Ci pełny kod i błąd:
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)
}
}
Oto sesja terminalu:
[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
Chyba, że jest coś, że tęskniłem od początku, że może wyjaśnić dlaczego jestem przyklejone na kilka tygodni!
Benoit
Edited 15 maja
Kompilacja kodu, mam pierwszy błąd:
could not find implicit value for parameter F: scalaz.Pointed[Main.$anon.ValidationTExample.WriterAlias]
Po kilku próbach I przepisał import w ten sposób:
import scalaz.Writer
import scalaz.std.string._
import scalaz.Id._
import scalaz.WriterT
import scalaz.ValidationT
import scala.Math._
Istnieje sti ll jeden błąd:
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
Ten błąd był obecny z kodem, który napisałeś maja 14. Oczywiście, trudno jest zrozumieć, co iimport dokładnie scalaz siedem. Używając wersji 6, wszystko wyglądało prościej: wystarczyło zaimportować scalaz._ i Scalaz._
Czuję się jak "zdesperowany domownik" :) (tak, zgadzam się, to nie jest zbyt przenikliwe, ale jest relaksujące!)
Benoit
23 maja
Ouf! Skutecznie działa z ostatnią wersją scalaz-seven: zauważ, że musiałem ją zbudować zamiast pobierać migawkę.
to świetnie!
Dla tych, którzy są zainteresowani, tutaj jest wyjście:
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 Osiem, jeśli przypadkowo spotykamy jeden dzień, Zapłacę ci piwo!
Benoit
Myślę, że twoja wersja skalaza-siedem nie jest dobra. Kod działa poprawnie z ostatnią wersją scalaz-seven branch –
Tęsknię za Twoim wpisem. Tak właśnie się domyślałem. Używam migawki z 14 kwietnia. Powinienem mieć czas na przetestowanie ostatniej wersji tego wieczoru. – bhericher