Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the benefits of currying?

I don't think I quite understand currying, since I'm unable to see any massive benefit it could provide. Perhaps someone could enlighten me with an example demonstrating why it is so useful. Does it truly have benefits and applications, or is it just an over-appreciated concept?

like image 501
user997112 Avatar asked Sep 13 '12 19:09

user997112


People also ask

What is currying explain with example?

Currying is when you break down a function that takes multiple arguments into a series of functions that each take only one argument. Here's an example in JavaScript: function add (a, b) { return a + b; } add(3, 4); // returns 7. This is a function that takes two arguments, a and b, and returns their sum.

Are curry dishes healthy?

Curries can provide many health benefits, and they don't have to be full of saturated fats. The spices used in curries, such as turmeric, ginger and chilli, are known for their potent anti-inflammatory properties, as well as being of benefit to heart health and possible anticancer benefits.


2 Answers

(There is a slight difference between currying and partial application, although they're closely related; since they're often mixed together, I'll deal with both terms.)

The place where I realized the benefits first was when I saw sliced operators:

incElems = map (+1)
--non-curried equivalent: incElems = (\elems -> map (\i -> (+) 1 i) elems)

IMO, this is totally easy to read. Now, if the type of (+) was (Int,Int) -> Int *, which is the uncurried version, it would (counter-intuitively) result in an error -- but curryied, it works as expected, and has type [Int] -> [Int].

You mentioned C# lambdas in a comment. In C#, you could have written incElems like so, given a function plus:

var incElems = xs => xs.Select(x => plus(1,x))

If you're used to point-free style, you'll see that the x here is redundant. Logically, that code could be reduced to

var incElems = xs => xs.Select(curry(plus)(1))

which is awful due to the lack of automatic partial application with C# lambdas. And that's the crucial point to decide where currying is actually useful: mostly when it happens implicitly. For me, map (+1) is the easiest to read, then comes .Select(x => plus(1,x)), and the version with curry should probably be avoided, if there is no really good reason.

Now, if readable, the benefits sum up to shorter, more readable and less cluttered code -- unless there is some abuse of point-free style done is with it (I do love (.).(.), but it is... special)

Also, lambda calculus would get impossible without using curried functions, since it has only one-valued (but therefor higher-order) functions.

* Of course it actually in Num, but it's more readable like this for the moment.


Update: how currying actually works.

Look at the type of plus in C#:

int plus(int a, int b) {..}

You have to give it a tuple of values -- not in C# terms, but mathematically spoken; you can't just leave out the second value. In haskell terms, that's

plus :: (Int,Int) -> Int, 

which could be used like

incElem = map (\x -> plus (1, x)) -- equal to .Select (x => plus (1, x))

That's way too much characters to type. Suppose you'd want to do this more often in the future. Here's a little helper:

curry f = \x -> (\y -> f (x,y))
plus' = curry plus

which gives

incElem = map (plus' 1)

Let's apply this to a concrete value.

incElem [1] 
= (map (plus' 1)) [1]
= [plus' 1 1]
= [(curry plus) 1 1]
= [(\x -> (\y -> plus (x,y))) 1 1]
= [plus (1,1)]
= [2]

Here you can see curry at work. It turns a standard haskell style function application (plus' 1 1) into a call to a "tupled" function -- or, viewed at a higher level, transforms the "tupled" into the "untupled" version.

Fortunately, most of the time, you don't have to worry about this, as there is automatic partial application.

like image 140
phipsgabler Avatar answered Sep 16 '22 19:09

phipsgabler


It's not the best thing since sliced bread, but if you're using lambdas anyway, it's easier to use higher-order functions without using lambda syntax. Compare:

map (max 4) [0,6,9,3] --[4,6,9,4]
map (\i -> max 4 i) [0,6,9,3] --[4,6,9,4]

These kinds of constructs come up often enough when you're using functional programming, that it's a nice shortcut to have and lets you think about the problem from a slightly higher level--you're mapping against the "max 4" function, not some random function that happens to be defined as (\i -> max 4 i). It lets you start to think in higher levels of indirection more easily:

let numOr4 = map $ max 4
let numOr4' = (\xs -> map (\i -> max 4 i) xs)
numOr4 [0,6,9,3] --ends up being [4,6,9,4] either way; 
                 --which do you think is easier to understand?

That said, it's not a panacea; sometimes your function's parameters will be the wrong order for what you're trying to do with currying, so you'll have to resort to a lambda anyway. However, once you get used to this style, you start to learn how to design your functions to work well with it, and once those neurons starts to connect inside your brain, previously complicated constructs can start to seem obvious in comparison.

like image 27
Dax Fohl Avatar answered Sep 16 '22 19:09

Dax Fohl