2013-07-17 57 views
6

我想在我的應用程序中使用Scalaz 7驗證。但是,我遇到了使用|@|應用函數來解決我的故障的問題。下面的代碼我有:Scalaz驗證與應用函子| @ |不工作

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])(_ |@| _) 
} 

minValidatesizeValidate功能只是返回ValidationResults

問題是,這段代碼不會編譯。錯誤信息是:

Type mismatch, expected F0.type#M[NotInferedB], actual: ValidationResult 

我不知道這意味着什麼...我需要給斯卡拉更多的類型信息?

我想要完成的是,如果所有字段都是successNel s,那麼返回,否則返回所有failureNel的組合。

已有|@|自從之前的Scalaz版本發生了變化?因爲即使我這樣做:

().successNel |@|().successNel 

我得到同樣的錯誤。

更新

我開始圍繞Scalaz源戳,我發現這似乎做我想做的+++

+++|@|有什麼區別?

回答

10

Scalaz的應用程序生成器語法(|@|)爲您提供了一種將函數「提升」爲應用函子的方法。假設我們有如下結果,例如:

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 

我們可以解除連接列表功能(++)到Validation這樣的:

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!)) 

這個語法是有點怪異,這是非常不同例如,如何將函數提升到Haskell的應用函子中,並且這種方式主要是用來勝過Scala相當愚蠢的類型推斷系統。有關更多討論,請參閱my answer hereblog post here

奇怪的一個部分是xs |@| ys本身並不意味着任何東西 - 它本質上是一個參數列表,它正在等待被應用到一個函數中,它將會提升到它的應用函子並應用於自身。

Validation+++一個更簡單的一種生物,它只是該類型Semigroup實例(請注意,您可以同樣使用Scalaz的半羣運營商|+|這裏代替+++)的加法運算。你給它兩個Validation匹配半羣類型的結果,它給你另一個Validation-不是一些可怕的ApplyOps事情。


作爲一個方面說明,在這種情況下,除了操作Validation的半羣是一樣的右側的半羣操作升高到Validation

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

這不會總是是這樣的,但是(例如,它不適用於\/,例如,半羣積累錯誤但應用函數不)。