2013-07-17 14 views
6

Ich versuche Scalaz 7 Validierung in meiner App zu verwenden. Allerdings habe ich ein Problem mit dem |@| Anwendungsfunktor, um meine Fehler zu koaleszieren. Hier ist der Code, den ich habe:Scalaz Validierung mit applicativem Funktor | @ | funktioniert nicht

type ValidationResult = ValidationNel[String, Unit] 

def validate[A: ClassTag](instance: A, fieldNames: Option[Seq[String]] = None): ValidationResult = { 
    val fields = classTag[A].runtimeClass.getDeclaredFields 
    val fieldSubset = fieldNames match { 
     case Some(names) => fields.filter { field => names.contains(field.getName) } 
     case None => fields 
    } 
    fieldSubset.map { 
     field => field.getAnnotations.toSeq.map { 
      field.setAccessible(true) 
      val (name, value) = (field.getName, field.get(instance)) 
      field.setAccessible(false) 
      annotation => annotation match { 
       case min: Min => minValidate(name, value, min.value()) 
       case size: Size => sizeValidate(name, value, size.min(), size.max()) 
      } 
     } 
    }.flatten[ValidationResult].foldLeft(().successNel[String])(_ |@| _) 
} 

Die minValidate und sizeValidate Funktionen nur ValidationResults zurückzukehren.

Das Problem ist, dieser Code wird nicht kompilieren. Die Fehlermeldung lautet:

Ich habe keine Ahnung, was das bedeutet ... muss ich Scala mehr Typ Info geben?

Was ich versuche zu erreichen ist, wenn alle Felder successNel s sind, dann gebe das zurück, andernfalls gebe eine Kombination aller failureNel s zurück.

Hat sich |@| seit der vorherigen Version von Scalaz geändert? Denn selbst wenn ich etwas mache wie:

().successNel |@|().successNel 

bekomme ich den gleichen Fehler.

aktualisieren

begann ich um die Scalaz Quelle Stossen und ich fand die +++ das, was zu tun scheint, ich will.

Was ist der Unterschied zwischen +++ und |@|?

Antwort

10

Scalaz's applikative Builder-Syntax (|@|) gibt Ihnen eine Möglichkeit, Funktionen in einen anwendungsbezogenen Funktor zu "heben". Angenommen, wir folgende Ergebnisse haben, zum Beispiel:

val xs: ValidationNel[String, List[Int]] = "Error!".failNel 
val ys: ValidationNel[String, List[Int]] = List(1, 2, 3).success 
val zs: ValidationNel[String, List[Int]] = List(4, 5).success 

Wir können die Liste Verkettung Funktion heben (++) in die Validation wie folgt aus:

scala> println((ys |@| zs)(_ ++ _)) 
Success(List(1, 2, 3, 4, 5)) 

scala> println((xs |@| ys)(_ ++ _)) 
Failure(NonEmptyList(Error!)) 

scala> println((xs |@| xs)(_ ++ _)) 
Failure(NonEmptyList(Error!, Error!)) 

Diese Syntax ist ein wenig seltsam, es ist sehr anders als Wie Sie zum Beispiel Funktionen in Haskell zu einem anwendungsbezogenen Funktoord erheben, und ist so entworfen, um Scala's ziemlich dummes Inferenzsystem zu überlisten. Weitere Informationen finden Sie unter my answer here oder blog post here. Ein Teil der Seltsamkeit ist, dass xs |@| ys nicht wirklich etwas bedeutet - es ist im Wesentlichen eine Argumentliste, die darauf wartet, auf eine Funktion angewendet zu werden, die sie in ihren anwendbaren Funktor auflöst und auf sich selbst anwenden wird.

Die +++ auf Validation ist eine viel einfachere Art von creature-es ist nur die Additionsoperation für das Semigroup Beispiel für die Art (beachten Sie, dass Sie in äquivalenter Weise Scalaz der Halbgruppe Betreiber |+| hier anstelle von +++ nutzen könnten). Sie geben es zwei Validation Ergebnisse mit passenden Halbgruppe Typen und es gibt Ihnen eine weitere Validation -not einige schreckliche ApplyOps Sache.


Als Randbemerkung, in diesem Fall die Additionsoperation für Validation ‚s Halbgruppe die gleiche wie die Halbgruppe Betrieb für die rechte Seite ist in die Validation gehoben:

scala> (xs |+| ys) == (xs |@| ys)(_ |+| _) 
res3: Boolean = true 

Dies wird nicht Dies ist jedoch immer der Fall (es ist nicht für , zum Beispiel, wo die Halbgruppe Fehler akkumuliert, aber der applikative Funktor nicht).