Open CauchyPeano opened 3 years ago
I love this idea ❤️ It is the simplest form of validation I can imagine!
I updated this comment, because we can't use flatMap. That idea was nonsense and my suggestion was even false.
What about the more flexible version with a higher order function?
-- equivalent to (<*)
andThen :: f a -> (a -> f b) -> f a
-- a generalization of (*>)
-- (<*) could be also expressed with it by setting c to a
andThenFold :: f a -> (a -> f b) -> (a -> b -> c) -> f c
Example:
// type Validation<String, BasicAuth>
var result = Validation.valid(new BasicAuth("user", "pass"))
// type Validation<String, User>
.andThenFold(App::validateCredentials, (basicAuth, grants) -> new User(basicAuth.user, grants))
// type Validation<String, User>
.andThen(App::validateUserGrants);
In Typelevel Cats, there exists andThen
as part of Sequential Validation. But in our case, we would additionally accumulate errors.
Hi Daniel,
I am very glad that you liked this idea!
Yeah, flatMap
idea was a bit confusing to me :)
I think andThen
and andThenFold
will work out really good. Name fits well. Also we don't need both right *>
and left <*
operations - only one is enough. If you don't mind I can make PR and maybe some examples as PoC.
Happy new year 🎉
I'm not sure how I'd do validation against more than eight fields. I wind up with a List<Validation<String,Long>> of arbitrary length but I don't know how to get it into Validation<Seq
If validation grows bigger, then we can use Validation.sequence
Is that what would apply in my case? I can't understand how to use it here.
@mattfara Sequence is really handy to work with arbitrary number of validations, but you need then to update validating functions accordingly.
public static void main(String[] args) {
Person person = new Person("Bob", "+12345", "bob@test.com");
Validation<Seq<String>, Seq<Person>> sequence =
Validation.sequence(List.of(validateEmail(person), validatePhone(person)));
// person will contain same reference, taking either p1 or p2, they still the same
Validation<Seq<String>, Person> result = sequence.map(seqP -> seqP.reduce((p1, p2) -> p2));
}
public static Validation<Seq<String>, Person> validateEmail(Person p) {
if (p.email == null) return Validation.invalid(List.of("Null email!"));
else return Validation.valid(p);
}
public static Validation<Seq<String>, Person> validatePhone(Person p) {
if (p.phoneNumber == null || !p.phoneNumber.startsWith("\\+"))
return Validation.invalid(List.of("Wrong phone!"));
else return Validation.valid(p);
}
Thank you for the help!
Sent from my iPhone
On Jan 12, 2022, at 4:31 PM, Igor Konoplyanko @.***> wrote:
@mattfara Sequence is really handy to work with arbitrary number of validations, but you need then to update validating functions accordingly.
public static void main(String[] args) { Person person = new Person("Bob", "+12345", ***@***.***"); Validation<Seq<String>, Seq<Person>> sequence = Validation.sequence(List.of(validateEmail(person), validatePhone(person))); // person will contain same reference, taking either p1 or p2, they still the same Validation<Seq<String>, Person> result = sequence.map(seqP -> seqP.reduce((p1, p2) -> p2)); } public static Validation<Seq<String>, Person> validateEmail(Person p) { if (p.email == null) return Validation.invalid(List.of("Null email!")); else return Validation.valid(p); } public static Validation<Seq<String>, Person> validatePhone(Person p) { if (p.phoneNumber == null || !p.phoneNumber.startsWith("\\+")) return Validation.invalid(List.of("Wrong phone!")); else return Validation.valid(p); }
— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you were mentioned.
I am really enjoying using
Validation
class provided by vavr library.But sometimes it is tedious to build validating logic for common use cases in Java.
Right now main use-case for
Validation
is to use it together with calls tocombine
. This allows us to collect all successful validation and pass them to constructor function.But usually in my experience you can already get an object from parser library and want to run validation over it. Then validating code might look like this:
If validation grows bigger, then we can use
Validation.sequence
. But still we need to provide a function to discard other results, e.g.reduce((a, b) -> a)
.What is missing there are useful functions that have equivalence in Haskell (couldn't find them in scalaz) :
Then code above might look like this:
This will make
Validation
much easier to use and easier to adopt. I am still not sure how to name those functions.