2012-06-23 68 views
9

我對scalaz相當陌生,而且我已經開始驗證。Flattening嵌套Scalaz驗證

我有如下形式的一些驗證功能:

def validateXyz(...): ValidationNEL[String, String] = ... 

然後我使用的是應用性的風格,以多種驗證相結合,然後調用另一個函數也返回一個驗證:

(validateXyz(...) |@| validateAbc(...)) { (first, second) => 
    otherFunction(first, second) 
} 

def otherFunction(first: String, second: String): ValidationNEL[String, String] = ... 

但是,當調用上述結果類型是:

def propagateF(result: NonEmptyList[String]): ValidationNEL[String, String] = result.fail 
def propagateV(result: ValidationNEL[String, String]) = result 

result.fold(propagateF, propagateV) 
// result type: ValidationNEL[String, String] 

此:

val result: ValidationNEL[String, ValidationNEL[String, String]] = ... 

我可以通過調用摺疊對結果有兩個功能,這只是傳播NEL作爲第一故障和第二剛剛傳播它的參數解壓縮此工作並返回正確的類型和結果。然而,它不覺得正確的解決方案,所以我必須錯過一些東西。我最後需要做些什麼來避免這種可怕的摺疊?

回答

8

您在這裏找的是monadic join

問題是,Validation本身並不是一個單子,因爲錯誤端攜帶的Semigroup結構不能被Monad保留。但是如果需要的話,你總是可以下載到單子中的Either。此功能由flatMap提供。

(validateXyz(...) |@| validateAbc(...))(otherFunction).flatMap(x => x) 

如果您在外面發生錯誤,結果將是該錯誤。如果您在成功中出現錯誤,則結果將是內部錯誤。否則結果將會成功。請注意,在內部和外部不可能出現錯誤。這就是爲什麼如果你想合併錯誤,你必須使用Applicative而不是Monad