2016-12-18 9 views
0

https://gist.github.com/satyagraha/897e427bfb5ed203e9d3054ac6705704 Scala Cats検証シナリオを投稿しましたが、これは妥当と思われますが、非常にすっきりした解決策は見つかりませんでした。Scala Catsで検証済みのものは、どのように順序付き検証を組み合わせることができますか

基本的に2段階の検証があり、個々のフィールドが検証され、内部のチェックのためにスローされるクラスコンストラクタが呼び出されます(一般に、これは私の制御下にありません。コード)。フィールドの検証に失敗した場合はコンストラクタを呼び出さず、コンストラクタの失敗も最終結果に組み込みます。 2フェーズのチェックでは、「フェイル・ファスト」が確実にここにあります。

これは操作でcats.data.Validatedフレームワークが処理するように見える種類のflatMapの問題です。しかし、私はコードで見ることができるように、問題に特にきれいな解決策を見つけることができませんでした。 cats.syntax.CartesianBuilderで利用できる操作はかなり限られており、それをandThen操作とリンクさせる方法がわかりませんでした。

注意しなければならない可能性のある猫の問題https://github.com/typelevel/cats/issues/1343があることに注意してください。

答えて

1

私は例外スローなものをラップするヘルパー二次関数になるだろう:

def attempt[A, B](f: A => B): A => Validated[Message, B] = a => tryNonFatal(f(a)) 

はまた、ケースクラスのデフォルトの仲間はFunctionN形質を拡張し、そう(User.apply _).tupledを行う必要はありません、それはUser.tupledに短縮することができます(カスタム仲間に、あなたはextends ((...) => ...))しかしapplyオーバーライドが自動生成されます記述する必要がある)

だから我々はを使用しているで終わります:

val valids = validateName(nameRepr) |@| validateDate(dateDepr) 
val res: Validated[Message, User] = valids.tupled andThen attempt(User.tupled) 
+0

これは良い解決策のように見え、より一般的なケースに拡張可能に見えます。ありがとう! – satyagraha

1

フェイル・ファスト・チェイン・バリデーションの場合、EitherValidatedよりも使用する方が簡単です。エラーの蓄積を希望する場合は、EitherからValidatedへ、またはその逆に簡単に切り替えることができます。

Userのスマートコンストラクタを作成してEither[Message, User]を返し、Validated[Message, (Name, Date)]でこれを使用すると問題が解決する可能性があります。

import cats.implicits._ 
import cats.data.Validated 

def user(name: Name, date: Date): Either[Message, User] = 
    Either.catchNonFatal(User(name, date)).leftMap(Message.toMessage) 

// error accumulation -> Validated 
val valids: Validated[Message, (Name, Date)] = 
    (validateName(nameRepr) |@| validateDate(dateDepr)).tupled 

// error short circuiting -> either 
val userOrMessage: Either[Message, User] = 
    valids.toEither.flatMap((user _).tupled) 

// Either[Message,User] = Right(User(Name(joe),Date(now))) 
関連する問題