How to harvest errors with validators?
See original GitHub issueComing from the great book “Functional Programming in C#”, I try to run a bunch of validators on an object and harvest all the errors that multiple different validators might find.
The book shows a solution where all errors are created by mapping the sequence of validators against their result when invoked with the test object.
So I come up with
List<Error> errors;
The problem now simply is: how do I instantiate my final Validation with this list of errors? I mean, a Validation<Error, T>
already knows how to handle a sequence of my Error
type!
The Prelude’s helper function though only accepts a single value for error. Why?
So this fails to compile:
{
var errors = validators
.Map(validate => validate(t))
.Bind(v => v.Match(Fail: errs=>Some(errs.Head), Succ: _ => None))
.ToList();
return errors.Count == 0
? Success<Error, T>(t)
: Fail(errors.ToSeq());
};
Because Prelude.Fail does only take ONE Error
, but not my sequence.
Can anybody explain to me how this might be done with Language Ext? Thanks!
Issue Analytics
- State:
- Created 5 years ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
@wawaforya There is already a mechanism to construct a
Validation
with a sequence of errors:Short circuiting happens when you use bind (i.e. a series of
from ... in ...
statements). If you think about it, this is necessary, because if I do this:Then allowing the computation to continue after
validX
has failed to extractx
would lead to operations on undefined state. So, the monadic operation must short cut. This is why the computation to gather all errors is an applicative operation: each term can be computed independently and then brought together for a final operation.Therefore you need to use
Apply
. If you look at theValidationTests.cs
unit tests, you’ll see all of these techniques in action:cardHolderV
,numberV
, andmonthYear
are threeValidation
monads. They’re grouped into a tuple:And then the extension method
Apply
is run on that tuple. Which, when give a three parameter lambda, can use the success values to generate a newCreditCard
value. If any fail, then the lambda doesn’t get called and the errors are aggregated.You may also notice that the
numberV
monad is generated by appending two other monads together:This can be done when all the monadic types in the expression are the same, and only care about the first successful result being returned. And so this will validate the the number is all digits and that it’s not longer than 16 characters. Again, the errors are aggregated.
monthYear
actually makes use of the monad to short-cut if anything fails. So, you can have the best of both worlds.I believe the example was something like
If I’m undertstanding you correctly you can do the following
Or
You can also convert the resulting
Validation
to anEither
You can find more examples at https://github.com/louthy/language-ext/blob/master/LanguageExt.Tests/ValidationTests.cs
Happy to know if there’s a better way though