10

私は scalaz にかなり慣れていないので、バリデーションから始めました。

次の形式の検証関数がいくつかあります。

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

次に、Applicative スタイルを使用して複数の検証を組み合わせ、検証を返す別の関数を呼び出します。

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

どこ、

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

ただし、上記を呼び出すと、結果の型は次のようになります。

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

2 つの関数を使用して結果に対して fold を呼び出すことで、これをアンパックできます。1 つ目は NEL を失敗として伝播し、2 つ目はその引数を伝播します。

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]

これは機能し、正しい型と結果を返します。しかし、それは正しい解決策のようには感じられないので、何かが欠けているに違いありません。最後にこの恐ろしいフォールドを避けるために何をする必要がありますか?

4

1 に答える 1

10

ここで探しているのはモナディックjoinです。

問題は、Validationそれ自体は実際にはモナドではないということです。なぜなら、エラー側は ではSemigroup保存できない構造を持っているからMonadです。Eitherしかし、必要に応じていつでもモナドにドロップダウンできます。この機能は によって提供されflatMapます。

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

外側にエラーがあれば、結果はそのエラーになります。成功の中にエラーがある場合、結果は内部エラーになります。それ以外の場合、結果は成功になります。内側と外側の両方でエラーが発生することはあり得ないことに注意してください。これが、エラーを組み合わせたい場合Applicativeではなく、使用する必要がある理由です。Monad

于 2012-06-24T00:02:26.977 に答える