Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to aggregate all success/failures in list of Validation (sequence?) #71

Closed
OliverJAsh opened this issue Feb 4, 2017 · 3 comments · Fixed by #79
Closed

How to aggregate all success/failures in list of Validation (sequence?) #71

OliverJAsh opened this issue Feb 4, 2017 · 3 comments · Fixed by #79

Comments

@OliverJAsh
Copy link

Hi, thanks for the fantastic library and learning resources.

I have Array<Validation<A, B>> and want to aggregate all the successes and failures, e.g. Array<Validation<A, B>> => Validation<Array<A>, Array<B>>.

I thought this was possible using control.monads.sequence, however I seem to get runtime error mr.chain is not a function, so I presume I must be doing something wrong.

I have had success sequencing a list of Eithers, but in my case I want to aggregate the left hand side as well, which from reading this blog post, it appears Validation should help.

Thanks!

@OliverJAsh
Copy link
Author

OliverJAsh commented Feb 4, 2017

Never mind, got it now!

// Array<Validation<A, B>> => Validation<Array<A>, Array<B>>
const sequenceValidations = validations => (
    validations
        .reduce((acc, validation) => (
            Validation.Success(a => b => a.concat(b)).ap(acc).ap(validation)
        ), Validation.of([]))
)

Is this function in the library anywhere?

@robotlolita
Copy link
Member

@OliverJAsh Validations implement Applicative, rather than Monad, so sequence (which uses the Monad's interface .chain) doesn't work on them.

There isn't a function to aggregate Validations yet. Validations themselves already aggregate failures when you use .apply(), but the failure needs to have a .concat method. You can write a function to do this as:

const Validation = require('folktale/data/validation');
const curry = require('folktale/core/lambda/curry');

const intoArray = (x) => Array.isArray(x) ? x : [x];

const collect = (validations) =>
  validations.map(x => x.failureMap(intoArray)).reduce(
    (a, b) => a.ap(b),
    Validation.of(curry(validations.length, (...values) => values))
  );

So something like:

collect([a, b, c]);

Translates to:

Validation.of((a, b, c) => [a, b, c])
  .ap(a.failureMap(intoArray))
    .ap(b.failureMap(intoArray))
      .ap(c.failureMap(intoArray))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants