I am trying to translate this JS fixed-point operator into Haskell.
JS:
const fix = F => {
const D = X => F(
t => X(X)(t)
)
return D(D)
};
My attempt is (Haskell):
fix' f = d d
where
d x = f (\t -> x x t)
However, I get the following error:
Couldn't match expected type ‘(t2 -> t3) -> t4’
with actual type ‘p’
because type variables ‘t2’, ‘t3’, ‘t4’ would escape their scope
These (rigid, skolem) type variables are bound by the inferred type of d :: (t1 -> t2 -> t3) -> t4
Does someone know what's happening here ?
In the self-application d d, d is both a function, of some type a -> r, and its argument, of type a. Thus the two types must be one and the same, a ~ (a -> r).
Haskell wants to know its types in full upfront so it keeps substituting one for another ending up with an infinite type.
Infinite types aren't allowed in Haskell, but recursive types are allowed.
All we need to do here is to name that recursive type:
newtype T r = D { app :: T r -> r }
Now T r is both a type of a function and its argument, for some result type r.
Here T is a type constructor, and D its data constructor, D :: (T r -> r) -> T r.
The above record syntax defines a new data type (here though with the keyword newtype, not data) and names its single field as app. It also defines app as an accessor function, app :: T r -> (T r -> r). (It's kind of an inverse of D, and oftentimes one sees such functions named with the prefix of "un", like app could have been named unD. But here app makes sense, as we will see later.)
For a value x of type T r, x :: T r, this means that x is / matches up with / some value D g where (g = app x) :: T r -> r, i.e. app simply unwraps the data constructor D to get to the underlying value (a function) g: x = D g ; app x = app (D g) = g. That's how the record syntax works in Haskell.
Now we can write
{- fix' f = d d
where
d x = f (\t -> x x t) -- applying x to x can't be typed!
-}
fix1 :: ((t1 -> t) -> t1 -> t) -> t1 -> t
fix1 f = d (D d)
where
d x = f (\t -> app x x t) -- `app`ing x to x is well-typed!
fix2 :: ((t1 -> t) -> t1 -> t) -> t1 -> t
fix2 f = d (D d)
where
d (D y) = f (\t -> y (D y) t)
fix3 :: ((t1 -> t) -> t1 -> t) -> t1 -> t
fix3 f = f (\t -> d (D d) t)
where
d (D y) = f (\t -> y (D y) t)
fix4 :: (t -> t) -> t
fix4 f = f (d (D d))
where
d (D y) = f (y (D y))
all work. The last one even has the same type as the built-in fix.
But Haskell doesn't only have recursive types. It also has recursion itself. An entity is allowed to refer to itself in its own definition.
Thus as the comments say we don't really need to emulate recursion by self-application of a value passed as an argument. We can just use recursively the function being defined, itself:
fix0 :: (t -> t) -> t
fix0 f = f (fix0 f)
Or we can use a recursively defined value:
y :: (t -> t) -> t
y f = x where { x = f x }
Regarding the error, the second type error you get,
prog.hs:3:22: error:
• Occurs check: cannot construct the infinite type:
t1 ~ t1 -> t2 -> t3
• In the first argument of ‘x’, namely ‘x’
In the expression: x x t
In the first argument of ‘f’, namely ‘(\ t -> x x t)’
• Relevant bindings include
t :: t2 (bound at prog.hs:3:15)
x :: t1 -> t2 -> t3 (bound at prog.hs:3:7)
d :: (t1 -> t2 -> t3) -> t4 (bound at prog.hs:3:5)
|
3 | d x = f (\t -> x x t)
| ^
seems more to-the-point / helpful / than the one you included.
I often find JavScript shortcuts useful, such as replacing if/else statements like
if (a !== 0) {
b = c;
} else {
b = d;
}
with
b = a ? c : d;
or replacing for/next loops like
for (let i = 0; i < array.length; i++) {
element = array[i];
/* do something with element... */
}
with
array.forEach(element => { /* do something with element... */ });
I especially like that these and other similar shortcuts can be combined and used inside parenthetical statements, such as
array.forEach(e => (x += e ? a : b, e * x));
(works)
However, I haven't been able to find a shortcut or functional equivalent to the "while" statement that works inside parentheses. Is there such a thing?
I tried to use a normal while statement inside parentheses, but I got an error
array.forEach(e => (while (e.length > 160) { e.replace(' ', ''); }, e));
(doesn't work)
I know the above can be rewritten in a longer form, like so
array.forEach(e => {
while (e.length > 160) {
e.replace(' ', '');
}
return e;
});
(works)
But there are times I'd really prefer an inline shorthand equivalent to while, rather than the long version. Is there a way to do that?
You can use recursion:
const cutSpace = str => str.length > 160
? cutSpace(str.replace(' ', ''))
: str
const trimmedStrings = array.map(cutSpace)
I especially like that these and other similar shortcuts can be combined and used inside parenthetical statements, such as
array.forEach(e => (x += e ? a : b, e * x));
(works)
What? In what capacity does this code "work"? If I saw this code in review, I'd reject it immediately.
External state mutation in a predicate?
Inside a loop, nonetheless?
Not to mention neither a nor b is used.
Not to mention the parentheses and trailing e * x expression is completely thrown away, too... (?)
It's so bad it hurts.
I tried to use a normal while statement inside parentheses, but I got an error
array.forEach(e => (while (e.length > 160) { e.replace(' ', ''); }, e));
(doesn't work)
Well it's a syntax error. You tried to use a statement where only expressions are allowed. Things like if, for, while, do are statements. You cannot put a statement in a (...) expression. Even if you could use a while expression here, the code still wouldn't do anything. Every computation is completely discarded
I know the above can be rewritten in a longer form, like so
array.forEach(e => {
while (e.length > 160) {
e.replace(' ', '');
}
return e;
});
(works)
"works"? How does this work? Syntactically it's OK, but it doesn't actually do anything.
Strings are immutable so String.prototype.replace will not mutate e like I think you're imaging it does.
Array.prototype.forEach ignores the return value in your iterator function
Array.prototype.forEach has no return value of its own
I can only assume you mean to do something like this
let input = [
'a b c d e f g h',
'i j k l m n o',
'p q r s t u',
'v w x y z'
]
input.forEach(e => {
while (e.length > 9)
e = e.replace(' ', '')
console.log(e)
})
// abcdefg h
// ijklm n o
// pqr s t u
// v w x y z
Do you see the difference? I'm using e = e.replace(...) because replace does not mutate the input string in place. Also, my iterator is actually doing something with the value – console.log, dumb as it might be
It seems tho like you might be unaware of Array.prototype.map. Like replace, map will not mutate the original input – instead, a new value is returned. So this time we assign the return value of the map to a new variable, output, and log that when we're done
let input = [
'a b c d e f g h',
'i j k l m n o',
'p q r s t u',
'v w x y z'
]
let output = input.map(e => {
while (e.length > 9)
e = e.replace(' ', '')
return e
})
console.log(output)
// [
// "abcdefg h",
// "ijklm n o",
// "pqr s t u",
// "v w x y z"
// ]
Neither of these last two code snippets are bad. The first one has an I/O side effect (console.log in the forEach) but the second one is entirely pure and entirely functional. There's nothing wrong with local mutation and there's nothing wrong with using while in your programs, especially considering no JavaScript VM that I know of supports tail call optimisation - recursion is actually not the bees knees in the land of JS.
This might not be shorter, but it is functional:
const array = [
' ',
' ',
' ',
' ',
' ',
' ',
' ',
'',
];
const result = array.map(e => (f => (g => x => f(g(g))(x))(h => x => f(h(h))(x)))(f => e => e.length > 2 && f(e.replace(' ', '')) || e)(e) );
console.log( result );
I changed 160 to 2 and used map instead of forEach to make it easier to demonstrate.
If you're doing a single command in the loop, you can use a for loop;
array.forEach(e => for(; e.length > 160; e.replace(' ', ''));return e;})
I'm learning functional programming and I wonder if there is a way to "combine" functions like this:
function triple(x) {
return x * 3;
}
function plusOne(x) {
return x + 1;
}
function isZero(x) {
return x === 0;
}
combine(1); //1
combine(triple)(triple)(plusOne)(1); // 10
combine(plusOne)(triple)(isZero)(-1); // true
If the para is a function, it "combines" the function into itself, and if not it will return the final result.
Thanks!
heritage
This is a concept from maths called function composition.
f(x) = y
g(y) = z
g(f(x)) = z
(g•f)(x) = z
That last line is read "g of f of x equals z". What's great about composed functions is the elimination of points. Notice in g(f(x)) = z we take an x input and get a z output. This skips the intermediate point, y.
Composition is a great way to create higher-order functions and keep your code sparkly clean. It's plain to see why we'd want this in our Javascript programs.
comp
JavaScript is a multi-paradigm language with rich support for functions. We can create a simple comp function, which combines two input functions, g and f, and results in a new function -
function triple(x) {
return x * 3
}
function plusOne(x) {
return x + 1
}
function comp(g, f) {
return function(x) {
return g(f(x)) // "g of f of x"
}
}
const myfunc =
comp(triple, plusOne)
console.log(myfunc(1))
Evaluation
triple(plusOne(1))
triple(2)
6
compose
Just as the question suggests, it's likely we will want to combine more than two functions. Below we write compose which takes all of the input functions and reduces them using our simple comp from above. If no functions are given, we return the empty function, identity -
const triple = (x) =>
x * 3
const plusOne = (x) =>
x + 1
const comp = (g, f) =>
x => g(f(x)) // "g of f of x"
const identity = (x) =>
x
const compose = (...all) =>
all.reduce(comp, identity)
const myfunc =
compose(triple, triple, plusOne) // any amount of funcs
console.log(myfunc(1))
Evaluation
triple(triple(plusOne(1)))
triple(triple(2))
triple(6)
18
pipe
You can be as creative as you like. Below, we write pipe which allows our programs to read in a comfortable left-to-right direction -
const triple = (x) =>
x * 3
const plusOne = (x) =>
x + 1
const pipe = x =>
f => pipe(f(x))
pipe(1)(plusOne)(triple)(triple)(console.log) // 18
pipe(3)(triple)(plusOne)(triple)(plusOne)(console.log) // 31
Evaluation of expression one -
f => pipe(f(1))
pipe(plusOne(1))
f => pipe(f(2))
pipe(triple(2))
f => pipe(f(6))
pipe(triple(6))
f => pipe(f(18))
pipe(console.log(18))
18
and expression two -
f => pipe(f(3))
pipe(triple(3))
f => pipe(f(9))
pipe(plusOne(9))
f => pipe(f(10))
pipe(triple(10))
f => pipe(f(30))
pipe(plusOne(31))
f => pipe(f(31))
pipe(console.log(31))
31
related techniques
Curried functions and partial application are concepts that gel with function composition. pipe above is introduced in another Q&A as $ and demonstrated again here -
const $ = x => // "pipe", or whatever name you pick
k => $ (k (x))
const add = x => y => // curried add
x + y
const mult = x => y => // curried mult
x * y
$ (1) // 1
(add (2)) // + 2 = 3
(mult (6)) // * 6 = 18
(console.log) // 18
$ (7) // 7
(add (1)) // + 1 = 8
(mult (8)) // * 8 = 64
(mult (2)) // * 2 = 128
(mult (2)) // * 2 = 256
(console.log) // 256
function triple(x) {
return x * 3;
}
function plusOne(x) {
return x + 1;
}
function isZero(x) {
return x === 0;
}
var combine = function (v) {
var fn = [];
function _f(v) {
if (typeof v === 'function') {
fn.push(v);
return _f;
} else {
return fn.reduce(function (x, f) { return f(x); }, v);
}
}
return _f(v);
};
var a, b;
console.log(combine(1)); //1
console.log(combine(triple)(triple)(plusOne)(1)); // 10
console.log(combine(plusOne)(triple)(isZero)(-1)); // true
console.log(a = combine(plusOne)); // function ...
console.log(b = a(triple)); // function ...
console.log(b(5)); // 18
console.log(combine(triple)(plusOne)(triple)(plusOne)(triple)(plusOne)(1)); // 40
// #naomik's examples
var f = combine(triple);
var g = combine(triple)(triple);
console.log(f(1)); // 3
console.log(g(1)); // 9 (not 6 as you stated)
Function composition has already been detailed in other answers, mostly https://stackoverflow.com/a/30198265/4099454, so my 2 cents are straight onto answering your latest question:
If the para is a function, it "combines" the function into itself, and if not it will return the final result. Thanks!
const chain = (g, f = x => x) =>
typeof g === 'function'
? (y) => chain(y, (x) => g(f(x)))
: f(g);
// ====
const triple = x => x * 3;
const inc = x => x + 1;
const isZero = x => x === 0;
console.log(
chain(inc)(triple)(isZero)(-1),
);
It is also possible to build a complex Functionality by Composing Simple Functions in JavaScript.In a sense, the composition is the nesting of functions, passing the result of one in as the input into the next. But rather than creating an indecipherable amount of nesting, we'll create a higher-order function, compose(), that takes all of the functions we want to combine, and returns us a new function to use in our app.
function triple(x) {
return x * 3;
}
function plusOne(x) {
return x + 1;
}
function isZero(x) {
return x === 0;
}
const compose = (...fns) => x =>
fns.reduce((acc, cur) => {
return cur(acc);
}, x);
const withCompose = compose(triple, triple, isZero);
console.log(withCompose(1));
You can simply call the function on the return values themselves, for example:
plusOne(triple(triple(1))) // 10
isZero(triple(plusOne(-1))) // true
I wrote a simple curry function in JavaScript which works correctly for most cases:
const curry = (f, ...a) => a.length < f.length
? (...b) => curry(f, ...a, ...b)
: f(...a);
const add = curry((a, b, c) => a + b + c);
const add2 = add(2);
const add5 = add2(3);
console.log(add5(5));
However, it doesn't work for the following case:
// length :: [a] -> Number
const length = a => a.length;
// filter :: (a -> Bool) -> [a] -> [a]
const filter = curry((f, a) => a.filter(f));
// compose :: (b -> c) -> (a -> b) -> a -> c
const compose = curry((f, g, x) => f(g(x)));
// countWhere :: (a -> Bool) -> [a] -> Number
const countWhere = compose(compose(length), filter);
According to the following question countWhere is defined as (length .) . filter:
What does (f .) . g mean in Haskell?
Hence I should be able to use countWhere as follows:
const odd = n => n % 2 === 1;
countWhere(odd, [1,2,3,4,5]);
However, instead of returning 3 (the length of the array [1,3,5]), it returns a function. What am I doing wrong?
#Aadit,
I'm posting this because you shared a comment on my answer to To “combine” functions in javascript in a functional way? I didn't specifically cover currying in that post because it's a very contentious topic and not really a can of worms I wanted to open there.
I'd be wary using the phrasing "how to correctly curry" when you seem to be adding your own sugar and conveniences into your implementation.
Anyway, all of that aside, I truly don't intend for this to be an argumentative/combative post. I'd like to be able to have an open, friendly discussion about currying in JavaScript while emphasizing some of the differences between our approaches.
Without further ado...
To clarify:
Given f is a function and f.length is n. Let curry(f) be g. We call g with m arguments. What should happen? You say:
If m === 0 then just return g.
If m < n then partially apply f to the m new arguments, and return a new curried function which accepts the remaining n - m arguments.
If m === n then apply f to the m arguments. If the result is a function then curry the result. Finally, return the result.
If m > n then apply f to the first n arguments. If the result is a function then curry the result. Finally, apply the result to the remaining m - n arguments and return the new result.
Let's see a code example of what #Aadit M Shah's code actually does
var add = curry(function(x, y) {
return function(a, b) {
return x + y + a + b;
}
});
var z = add(1, 2, 3);
console.log(z(4)); // 10
There are two things happening here:
You're attempting to support calling curried functions with variadic arguments.
You're automatically currying returned functions
I don't believe there's a lot of room for debate here, but people seem to miss what currying actually is
via: Wikipedia
In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument...
I'm bolding that last bit, because it's so important; each function in the sequence only takes a single argument; not variadic (0, 1, or more) arguments like you suggest.
You mention haskell in your post, too, so I assume you know that Haskell has no such thing as functions that take more than one argument. (Note: a function that takes a tuple is still just a function that takes one argument, a single tuple). The reasons for this are profound and afford you a flexibility in expressiveness not afforded to you by functions with variadic arguments.
So let's re-ask that original question: What should happen?
Well, it's simple when each function only accepts 1 argument. At any time, if more than 1 argument is given, they're just dropped.
function id(x) {
return x;
}
What happens when we call id(1,2,3,4)? Of course we only get the 1 back and 2,3,4 are completely disregarded. This is:
how JavaScript works
how Wikipedia says currying should work
how we should implement our own curry solution
Before we go further, I'm going to use ES6-style arrow functions but I will also include the ES5 equivalent at the bottom of this post. (Probably later tonight.)
another currying technique
In this approach, we write a curry function that continuously returns single-parameter functions until all arguments have been specified
As a result of this implementation we have 6 multi-purpose functions.
// no nonsense curry
const curry = f => {
const aux = (n, xs) =>
n === 0 ? f (...xs) : x => aux (n - 1, [...xs, x])
return aux (f.length, [])
}
// demo
let sum3 = curry(function(x,y,z) {
return x + y + z;
});
console.log (sum3 (3) (5) (-1)); // 7
OK, so we've seen a curry technique that is implemented using a simple auxiliary loop. It has no dependencies and a declarative definition that is under 5 lines of code. It allows functions to be partially applied, 1 argument at a time, just as a curried function is supposed to work.
No magic, no unforeseen auto-currying, no other unforeseen consequences.
But what really is the point of currying anyway?
Well, as it turns out, I don't really curry functions that I write. As you can see below, I generally define all of my reusable functions in curried form. So really, you only need curry when you want to interface with some functions that you don't have control over, perhaps coming from a lib or something; some of which might have variadic interfaces!
I present curryN
// the more versatile, curryN
const curryN = n => f => {
const aux = (n, xs) =>
n === 0 ? f (...xs) : x => aux (n - 1, [...xs, x])
return aux (n, [])
};
// curry derived from curryN
const curry = f => curryN (f.length) (f);
// some caveman function
let sumN = function() {
return [].slice.call(arguments).reduce(function(a, b) {
return a + b;
});
};
// curry a fixed number of arguments
let g = curryN (5) (sumN);
console.log (g (1) (2) (3) (4) (5)); // 15
To curry or not to curry? That is the question
We'll write some examples where our functions are all in curried form. Functions will be kept extremely simple. Each with 1 parameter, and each with a single return expression.
// composing two functions
const comp = f => g => x => f (g (x))
const mod = y => x => x % y
const eq = y => x => x === y
const odd = comp (eq (1)) (mod (2))
console.log (odd(1)) // true
console.log (odd(2)) // false
Your countWhere function
// comp :: (b -> c) -> (a -> b) -> (a -> c)
const comp = f => g => x =>
f(g(x))
// mod :: Int -> Int -> Int
const mod = x => y =>
y % x
// type Comparable = Number | String
// eq :: Comparable -> Comparable -> Boolean
const eq = x => y =>
y === x
// odd :: Int -> Boolean
const odd =
comp (eq(1)) (mod(2))
// reduce :: (b -> a -> b) -> b -> ([a]) -> b
const reduce = f => y => ([x,...xs]) =>
x === undefined ? y : reduce (f) (f(y)(x)) (xs)
// filter :: (a -> Boolean) -> [a] -> [a]
const filter = f =>
reduce (acc => x => f (x) ? [...acc,x] : acc) ([])
// length :: [a] -> Int
const length = x =>
x.length
// countWhere :: (a -> Boolean) -> [a] -> Int
const countWhere = f =>
comp (length) (filter(f));
console.log (countWhere (odd) ([1,2,3,4,5]))
// 3
Remarks
So to curry or not to curry?
// to curry
const add3 = curry((a, b, c) =>
a + b + c
)
// not to curry
const add3 = a => b => c =>
a + b + c
With ES6 arrow functions being the go-to choice for today's JavaScripter, I think the choice to manually curry your functions is a no-brainer. It's actually shorter and has less overhead to just write it out in curried form.
That said, you're still going to be interfacing with libs that do not offer curried forms of the functions they expose. For this situation, I'd recommend
curry and curryN (defined above)
partial (as defined here)
#Iven,
Your curryN implementation is very nice. This section exists solely for you.
const U = f=> f (f)
const Y = U (h=> f=> f(x=> h (h) (f) (x)))
const curryN = Y (h=> xs=> n=> f=>
n === 0 ? f(...xs) : x=> h ([...xs, x]) (n-1) (f)
) ([])
const curry = f=> curryN (f.length) (f)
const add3 = curry ((x,y,z)=> x + y + z)
console .log (add3 (3) (6) (9))
The problem with your curry function (and for most curry functions that people write in JavaScript) is that it doesn't handle extra arguments correctly.
What curry does
Suppose f is a function and f.length is n. Let curry(f) be g. We call g with m arguments. What should happen?
If m === 0 then just return g.
If m < n then partially apply f to the m new arguments, and return a new curried function which accepts the remaining n - m arguments.
Otherwise apply f to the m arguments and return the result.
This is what most curry functions do, and this is wrong. The first two cases are right, but the third case is wrong. Instead, it should be:
If m === 0 then just return g.
If m < n then partially apply f to the m new arguments, and return a new curried function which accepts the remaining n - m arguments.
If m === n then apply f to the m arguments. If the result is a function then curry the result. Finally, return the result.
If m > n then apply f to the first n arguments. If the result is a function then curry the result. Finally, apply the result to the remaining m - n arguments and return the new result.
The problem with most curry functions
Consider the following code:
const countWhere = compose(compose(length), filter);
countWhere(odd, [1,2,3,4,5]);
If we use the incorrect curry functions, then this is equivalent to:
compose(compose(length), filter, odd, [1,2,3,4,5]);
However, compose only accepts three arguments. The last argument is dropped:
const compose = curry((f, g, x) =>f(g(x)));
Hence, the above expression evaluates to:
compose(length)(filter(odd));
This further evaluates to:
compose(length, filter(odd));
The compose function expects one more argument which is why it returns a function instead of returning 3. To get the correct output you need to write:
countWhere(odd)([1,2,3,4,5]);
This is the reason why most curry functions are wrong.
The solution using the correct curry function
Consider the following code again:
const countWhere = compose(compose(length), filter);
countWhere(odd, [1,2,3,4,5]);
If we use the correct curry function, then this is equivalent to:
compose(compose(length), filter, odd)([1,2,3,4,5]);
Which evaluates to:
compose(length)(filter(odd))([1,2,3,4,5]);
Which further evaluates to (skipping an intermediate step):
compose(length, filter(odd), [1,2,3,4,5]);
Which results in:
length(filter(odd, [1,2,3,4,5]));
Producing the correct result 3.
The implementation of the correct curry function
Implementing the correct curry function in ES6 is straightforward:
const curry = (f, ...a) => {
const n = f.length, m = a.length;
if (n === 0) return m > n ? f(...a) : f;
if (m === n) return autocurry(f(...a));
if (m < n) return (...b) => curry(f, ...a, ...b);
return curry(f(...a.slice(0, n)), ...a.slice(n));
};
const autocurry = (x) => typeof x === "function" ? curry(x) : x;
Note that if the length of the input function is 0 then it's assumed to be curried.
Implications of using the correct curry function
Using the correct curry function allows you to directly translate Haskell code into JavaScript. For example:
const id = curry(a => a);
const flip = curry((f, x, y) => f(y, x));
The id function is useful because it allows you to partially apply a non-curried function easily:
const add = (a, b) => a + b;
const add2 = id(add, 2);
The flip function is useful because it allows you to easily create right sections in JavaScript:
const sub = (a, b) => a - b;
const sub2 = flip(sub, 2); // equivalent to (x - 2)
It also means that you don't need hacks like this extended compose function:
What's a Good Name for this extended `compose` function?
You can simply write:
const project = compose(map, pick);
As mentioned in the question, if you want to compose length and filter then you use the (f .) . g pattern:
What does (f .) . g mean in Haskell?
Another solution is to create higher order compose functions:
const compose2 = compose(compose, compose);
const countWhere = compose2(length, fitler);
This is all possible because of the correct implementation of the curry function.
Extra food for thought
I usually use the following chain function when I want to compose a chain of functions:
const chain = compose((a, x) => {
var length = a.length;
while (length > 0) x = a[--length](x);
return x;
});
This allows you to write code like:
const inc = add(1);
const foo = chain([map(inc), filter(odd), take(5)]);
foo([1,2,3,4,5,6,7,8,9,10]); // [2,4,6]
Which is equivalent to the following Haskell code:
let foo = map (+1) . filter odd . take 5
foo [1,2,3,4,5,6,7,8,9,10]
It also allows you to write code like:
chain([map(inc), filter(odd), take(5)], [1,2,3,4,5,6,7,8,9,10]); // [2,4,6]
Which is equivalent to the following Haskell code:
map (+1) . filter odd . take 5 $ [1,2,3,4,5,6,7,8,9,10]
Hope that helps.
Apart from its mathematical definition
currying is the transformation of a function with n parameters into a sequence of n functions, which each accept a single parameter. The arity is thus transformed from n-ary to n * 1-ary
what impact has currying on programming? Abstraction over arity!
const comp = f => g => x => f(g(x));
const inc = x => x + 1;
const mul = y => x => x * y;
const sqr = x => mul(x)(x);
comp(sqr)(inc)(1); // 4
comp(mul)(inc)(1)(2); // 4
comp expects two functions f and g and a single arbitrary argument x. Consequently g must be an unary function (a function with exactly one formal parameter) and f too, since it is fed with the return value of g. It won't surprise anyone that comp(sqr)(inc)(1) works. sqr and inc are both unary.
But mul is obviously a binary function. How on earth is that going to work? Because currying abstracted the arity of mul. You can now probably imagine what a powerful feature currying is.
In ES2015 we can pre-curry our functions with arrow functions succinctly:
const map = (f, acc = []) => xs => xs.length > 0
? map(f, [...acc, f(xs[0])])(xs.slice(1))
: acc;
map(x => x + 1)([1,2,3]); // [2,3,4]
Nevertheless, we need a programmatic curry function for all functions out of our control. Since we learned that currying primarily means abstraction over arity, our implementation must not depend on Function.length:
const curryN = (n, acc = []) => f => x => n > 1
? curryN(n - 1, [...acc, x])(f)
: f(...acc, x);
const map = (f, xs) => xs.map(x => f(x));
curryN(2)(map)(x => x + 1)([1,2,3]); // [2,3,4]
Passing the arity explicitly to curryN has the nice side effect that we can curry variadic functions as well:
const sum = (...args) => args.reduce((acc, x) => acc + x, 0);
curryN(3)(sum)(1)(2)(3); // 6
One problem remains: Our curry solution can't deal with methods. OK, we can easily redefine methods that we need:
const concat = ys => xs => xs.concat(ys);
const append = x => concat([x]);
concat([4])([1,2,3]); // [1,2,3,4]
append([4])([1,2,3]); // [1,2,3,[4]]
An alternative is to adapt curryN in a manner that it can handle both multi-argument functions and methods:
const curryN = (n, acc = []) => f => x => n > 1
? curryN(n - 1, [...acc, x])(f)
: typeof f === "function"
? f(...acc, x)
: x[f](...acc);
curryN(2)("concat")(4)([1,2,3]); // [1,2,3,4]
I don't know if this is the correct way to curry functions (and methods) in Javascript though. It is rather one possible way.
EDIT:
naomik pointed out that by using a default value the internal API of the curry function is partially exposed. The achieved simplification of the curry function comes thus at the expense of its stability. To avoid API leaking we need a wrapper function. We can utilize the U combinator (similar to naomik's solution with Y):
const U = f => f(f);
const curryN = U(h => acc => n => f => x => n > 1
? h(h)([...acc, x])(n-1)(f)
: f(...acc, x))([]);
Drawback: The implementation is harder to read and has a performance penalty.
//---Currying refers to copying a function but with preset parameters
function multiply(a,b){return a*b};
var productOfSixNFiveSix = multiply.bind(this,6,5);
console.log(productOfSixNFive());
//The same can be done using apply() and call()
var productOfSixNFiveSix = multiply.call(this,6,5);
console.log(productOfSixNFive);
var productOfSixNFiveSix = multiply.apply(this,[6,5]);
console.log(productOfSixNFive);