Looking at the source for Ramda.js, specifically at the \"lift\" function.
lift
liftN
Here\'s the given example:
var madd3 = R.lift(R
lift/liftN "lifts" an ordinary function into an Applicative context.
// lift1 :: (a -> b) -> f a -> f b
// lift1 :: (a -> b) -> [a] -> [b]
function lift1(fn) {
return function(a_x) {
return R.ap([fn], a_x);
}
}
Now the type of ap (f (a->b) -> f a -> f b) isn't easy to understand either, but the list example should be understandable.
The interesting thing here is that you pass in a list and get back a list, so you can repeatedly apply this as long as the function(s) in the first list have the correct type:
// lift2 :: (a -> b -> c) -> f a -> f b -> f c
// lift2 :: (a -> b -> c) -> [a] -> [b] -> [c]
function lift2(fn) {
return function(a_x, a_y) {
return R.ap(R.ap([fn], a_x), a_y);
}
}
And lift3, which you implicitly used in your example, works the same - now with ap(ap(ap([fn], a_x), a_y), a_z).