2016-02-16 78 views
5

在ScalaZ中,將Option[Validation[E, A]]轉換爲Validation[E, Option[A]]的慣用方法是什麼?將選項[驗證[E,A]]轉換爲驗證[E,選項[A]]

例如,在下面的假想代碼:

def convert(x: Option[Validation[E, A]]): Validation[E, Option[A]] =  
    /* ??? */ 

def validateThing(thing: A): Validation[E, A] = 
    /* whatever */ 

def exampleUseCase(maybeThing: Option[Thing]): Validation[E, Option[Thing]] = { 
    val validated: Option[Validation[E, Thing]] = a.map(validateThing(_)) 

    // ... 

    val result: Validation[E, Option[Thing]] = convert(validated) 
    result 
} 

什麼會的convert實施看起來像地道ScalaZ?

+1

我會說這個轉換對我來說沒有多大意義。如果'maybeThing'是'None',你會期望什麼結果?可能失敗的驗證,它沒有,如果它不是,那麼你可以提取價值,並把如果作爲一個'成功'的情況下,那麼你不需要'選項'。 – 4lex1v

+0

'validate'和'validateThing'是假設的,只是爲了顯示這種轉換可能發生的地方。我只關心'convert'的實現是什麼。 – kes

+0

但是,當'maybeThing'爲'None'時,回答具體的問題:成功驗證'None'。 – kes

回答

4

我可以在這裏看到兩種可能的解決方案。也許最簡單的一個使用的參數,例如模式匹配:

def convert[A](v: Option[Validation[Throwable, A]]): Validation[Throwable, Option[A]] = { 
    v match { 
    case None => Validation.success(None) 
    case Some(valid) => valid.map(Some(_)) 
    } 
} 

對於基於Scalaz的解決方案,我在想sequence,這樣,你需要使用ValidationNel而不是驗證,彙總可能出現的問題時,你可以實施convertTraversable

def convert[A](v: Option[ValidationNel[Throwable, A]]): ValidationNel[Throwable, Option[A]] = 
    Traverse[Option].sequenceU(v) 

請注意,其實我使用sequenceU,而不是僅僅sequence,沒什麼比內部Scalaz魔法更正確類型推斷,導致驗證有兩個類型參數。希望它有幫助

+2

如果您已經導入了所有內容或至少是'std.option._'和'syntax.traverse._',那麼您只需編寫'c.sequenceU'。 –