Skip to content
This repository has been archived by the owner on Mar 28, 2023. It is now read-only.

Consider providing a concat function #14

Open
iliocatallo opened this issue Apr 19, 2016 · 3 comments
Open

Consider providing a concat function #14

iliocatallo opened this issue Apr 19, 2016 · 3 comments

Comments

@iliocatallo
Copy link

iliocatallo commented Apr 19, 2016

Hi,

It would be handy to have Validation provide a concat function. Something like:

const R = require('ramda');

const concat = (v1, v2) =>
    v1.cata({
        Failure: (f1) => v2.isSuccess ? v1 : v2.failureMap(R.concat(f1)),
        Success: (s1) => v2
    });

Thanks.

@robotlolita
Copy link
Member

robotlolita commented Apr 19, 2016

The Applicative instance for Validation already does that, it's the major difference between Validation and Either:

var v1 = Validation.Failure([1])
var v2 = Validation.Failure([2])

v1.ap(v2)  
// => Validation.Failure([1, 2])

Validation.Success(x => 1).ap(v1) 
// => Validation.Failure([1])

Validation.Success(x => x + 1).ap(Validation.Success(1)) 
// => Validation.Success(2)

edit: The example in the README shows a more detailed scenario for this

@iliocatallo
Copy link
Author

iliocatallo commented Apr 21, 2016

Hi!

As you show, it is possible to achieve the desired behavior when Validation is used to lift a n-ary function. This is very useful when, e.g., in need of binding HTTP parameters to a form bean object:

Validation.Success(R.construct(FormBean))
.ap(validateFirstParam(body.firstParam))
.ap(validateSecondParam(body.secondParam));

However, what if I have some unrelated values – each of which wrapped in a Validation – and I would like to concatenate elements in the failure side?

const v1 = Validation.Success(12);
const v2 = Validation.Failure(['error']);

Since v1 does not wrap a function, I would assume it is not possible to apply v2 to it. For such cases, do we need concat or am I missing something?

Thanks!

@robotlolita
Copy link
Member

You can't use it directly without transforming the data, yes. I plan to include a function like this in the current redesign (origamitower/folktale#5) of the Folktale libraries, but that's going to take a while still (a couple of months, maybe?)

In the mean time, you can use the following function for this:

// Any function that curries with an explicit arity
var curry = require('core.lambda').curry;

//: (Array<Validation<Any, Error:Any>>, a) -> Validation<Array<Any>, Array<Error:Any>>
function collectFailures(validations) {
  const ap          = (acc, validation) => acc.ap(validation);
  const toList      = (...args) => args;
  const liftToArray = (value) => Array.isArray(value)? value : [value];

  return validations.map(validation => validation.failureMap(liftToArray))
                    .reduce(ap, Success(curry(validations.length, toList)))
}

// Then use it like:
const v1 = Validation.Success(12);
const v2 = Validation.Failure(['error']);
const v3 = Validation.Failure('another error');

collectFailures([v1, v2]) // => Success([12])
collectFailures([v2, v3]) // => Failure(['error', 'another error'])

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

No branches or pull requests

2 participants