Validator
に (validateToEither
と同様な)validateToAp
みたいなのを作らずApplicativeValidator
を別に用意したのは何故なんでしょう?validateToValidation
みたいな謎な名前になってしまうから?
- ApplicativeBuilder的な
ComposingN
があるのでFunctionN
にcurried
を持たせなくても良さそうですね(実装は泥臭くなりますがオブジェクト生成数を抑制できます)- 逆にカリー化できる関数があると
ComposingN
のようなものを不要にできたりもします。 - とは言えYAVIのユースケースだと
Validator
からメソッドチェーンで使うのが主だと思うので、ComposingN
の方が有用そうですね。 - 完全に余談ですが、カリー化できる
FunctionN
を別途定義するより、curried
を static メソッドにするとcurried(Foo::bar)
みたいな使い方が可能になるので個人的にはそちらの方がお勧めです。(Functions
的な1クラスのoverloadですませられますし)
- 逆にカリー化できる関数があると
Validation<E, >
のapply
がValidation<List<E>, >
を返すのがびっくりしますね。Applicative の挙動を期待するなら型としてはValidation<E, >
になるので。- YAVI の利用範囲から考えると、エラーの集約方法を汎用化する必要もなさそうなので、error は最初から
List
に決め打ちしちゃってもいいかもしれません。以下のようなイメージです。 -
public interface Validation<E, T> extends Serializable { boolean isValid(); T value(); List<E> error(); ...
- 名前があれであれば
ValidationNel
とかValidationL
とか? - 元のコードで
Validation<ConstraintViolations, >
だったものもValidationL<ConstraintViolation, >
にするイメージですね。
- YAVI の利用範囲から考えると、エラーの集約方法を汎用化する必要もなさそうなので、error は最初から
- せっかく Applicative な結果ができたので
sequence
/traverse
が欲しくなりますね。-
Validator<Email> emailValidator = ValidatorBuilder.of(Email.class) .constraint(...) .build() .prefixed("email"); List<Email> mails = List.of(...); ValidationL<ConstraintViolation, List<Email>> validated = ValidationL.traverse(mails, emailValidator.applicative()::validate);
- List に特化するよりは Collector化してStreamにできる全コンテナに対応してもいいかもです。参考 https://gist.github.com/gakuzzzz/0c779d5335f4b2bff596#traverse-%E3%81%A8-sequence
-
- 本筋とは関係ないですが様々なところで上限境界や下限境界を使ってないのは意図的なんでしょうか?
Last active
May 20, 2021 10:32
-
-
Save gakuzzzz/6acd31a9c7d1756ae6c2745442720a79 to your computer and use it in GitHub Desktop.
YAVI に Applicative な Validation 入れるよの話
accumulate
, and
, combine
だと combine
が個人的にはいいかなと思います。 vavr に寄せるの賛成 👍
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
vavrに寄せて
combine
に変更してみます。