Closed jk121960 closed 4 years ago
Hi @jk121960 the reason why this is failing on the third .ap
is because the way Apply works is by evaluating the function wrapped in the Success
with the value given to the .ap
function which must be a Validation
type as well.
So in your sample code, what is happening is that the first .ap
will evaluate with the first function wrapped in the Success
:
Success( function firstFn( a ) {
return function SecondFn( b ) {
// No more functions :(
return target;
}
}
Which returns us a new function that we can evaluate with the second .ap( isGreaterThan0( target ) )
but this second function returns us the value target
so by the time we get to the third .ap( isLessThan10( target ) )
we run out of functions that we can "Apply" values to and an error occurs as .ap
is expecting to have a function wrapped withing it.
If you wish to do this, I would advise you to use .concat
better, like this:
const isEven = function(num) {
return num % 2 === 0
? Success(num)
: Failure(["You must provide an even number"]);
};
const isGreaterThan0 = function(num) {
return num > 0
? Success(num)
: Failure(["You must provide a number greater than zero"]);
};
const isLessThan10 = function(num) {
return num < 10
? Success(num)
: Failure(["You must provide a numeber less than ten"]);
};
const isNumber = function(num) {
return typeof num === "number"
? Success(num)
: Failure(["You must provide a number!"]);
}
const isNumberValid = function(target) {
return Success()
.concat(isNumber(target))
.concat(isEven(target))
.concat(isGreaterThan0(target))
.concat(isLessThan10(target));
};
isNumberValid(8).matchWith({
Success: function(result) {
console.log("Value is valid!", result.value);
},
Failure: function(errors) {
// This will be an array of error messages in the order in which they were added
console.log("Values failed validation", errors.value);
}
});
Apply is used whenever you have a curried function which takes multiple arguments, arguments that will come from different Validation instances, like in this example:
const hasValidFirstname = input =>
input.firstname && input.firstname.trim()
? Success(input.firstname)
: Failure(["The firstname must not be empty"]);
const hasValidLastname = input =>
input.lastname && input.lastname.trim()
? Success(input.lastname)
: Failure(["The lastname must not be empty"]);
const hasValidAge = input =>
input.age && typeof input.age === "number"
? Success(input.age)
: Failure(["The age must be a valid number"]);
const areInputsValid = target =>
Validation.of(firstname => lastname => age => {
// This will be returned if no Failure happens along the way
return {
userInfo: {
firstname,
lastname,
age
}
}
})
.ap(hasValidFirstname(target))
.ap(hasValidLastname(target))
.ap(hasValidAge(target));
areInputsValid({
firstname: "John",
lastname: "Doe",
age: 39
}).matchWith({
Success: ({ value }) => console.log("Success:", value),
Failure: ({ value }) => console.log("Failed:", value)
})
Hope this has cleared up things for you :)
Sorry for the extremely late reply but I don't remember getting a notification. The ap code I was attempting to use I had gotten originally from the folktale site. I had discovered since then the concat approach on folktale 2. But at least I wasn't doing something stupid and not noticing it. So thanks for the sanity check and I appreciate your explanations thanks very much, I totally get it now.
When I use the applicative of Validation the first two predicates work fine but the third always throws an error stating that fn is not a function. Basically on the third in the sequence is passes the target monad rather than the function to the map of the applicative. I did try Gitter but no one had been there since Mar 30th
Steps to reproduce
I just have to add at least 3 predicates to the applicative sequence. the form of this I am using is: I have also noticed that this happens when all of the predicates return "Success" If I have errors is doesn't happen
var isNumberValid = function( target ) { return Success( function( a ) { return function( b ) { return target; } } ) .ap( isEven( target ) ) .ap( isGreaterThan0( target ) ) .ap( isLessThan10( target ) ) // .ap( isOdd( target ) )
};
var t1 = isNumberValid( 8 );
Expected behaviour
in the case of all true from the predicates I expect to receive the original target value back, and that is when it occurs, when I have errors the bug does not show.
Observed behaviour
when all predicates return true the problem manifests whenever I have at least 3 predicates. It occurs on the third when the applicative passes when should be a function in a monad, it passes the original target value in a monad
Environment
(Describe the environment where the problem happens. This usually includes:
Additional information
(Anything else you feel relevant to the issue)