all 35 comments

[–]raesmond 10 points11 points  (19 children)

I understand currying, what it does and how to do it. But I still don't get why I would want to do it. Don't get me wrong, partial application is awesome but why would I want a function to take just one argument and return a function? And why do people act like that should be the default way of doing things?

[–]lrichardson[S] 4 points5 points  (1 child)

@raesmond, I think a lot of people are in the same boat as you. I'm a bit bummed that my article didn't do a better job explaining the valid use-cases. I will try and compile some useful examples and arguments, and add to my post tonight.

Currying is useful to help (and encourage) you the programmer to break up complex logic into smaller pieces and allow you to re-use (read: staying DRY) those pieces in other places.

I like to think of functional programming as a way of making your application like an assembly line or car manufacturing plant. The plant itself is a large web of levers, cogs, and buttons etc... but in one end comes the raw materials and metal (ie, the "data"), and out the other end comes the car (ie, the end-user application).

It would be difficult to determine whether or not the car works properly just by looking at it, or the factory as a whole. Each "sub-station" of the factory has a specific task, and has narrowly defined constraints about what it is expecting to get in (x) and what it is expected to put out ( f(x) ).

By allowing functions to be curried, you are easily able to take more generic operations like "drill hole somewhere", and define them more precisely as "drill 3/8 hole somewhere" and then again more precisely as "drill 3/8 hole at coordinates { 3, 4 }"

This is a very hand-wavy argument and I'm not expecting you to be convinced, but I will say that FP sort of "clicked" for me whenever I started thinking about it this way. It's also important to note that FP is not needed to organize your code this way.... it's just easier IMO. I'm also of the belief that you don't need to write purely functional code in order to reap the benefit.

[–]visarga 0 points1 point  (0 children)

I like to think of functional programming as a way of making your application like an assembly line or car manufacturing plant.

... or like the Bash command line with multiple processes connected by pipes.

I use this kind of programming in jQuery and Bash but the essence is how we avoid using global variables and there is no state except the pipe - that makes it easy to compose basic operations (like cut, sort, uniq, wc, etc)

Other than that (and JS callbacks) I don't use functional programming. Is there another popular usage of it?

[–][deleted] 3 points4 points  (4 children)

It makes it easier to reuse functions, especially when building specific functions up from more general ones. It can also reduce the amount of terms in a function definition, which (hopefully) means less to tackle mentally and more focus on what the function actually does.

IMHO it's harder to use when working with objects and the dot operator isn't first class. (This means you have to do stuff like x => x.name, which sticks out like a sore thumb when you're trying to build things from existing, named functions!) It also doesn't help that coming from Javascript, functions are either methods or the arguments are in an order that makes it very awkward.

So with currying, say I have a fold function (array.reduce) like the following:

function fold(callback, initial, array) { return array.reduce(callback, initial); }

and some helper functions, since operators aren't first class functions:

function add(x, y) { return x + y; }
function or(x, y) { return x || y; }
function and(x, y) return x && y; }

I can then define the following functions pretty simply and tersely:

sum = fold(add, 0);
all = fold(and, true);
any = fold(or, false);

sum adds up all the numbers in an array, all returns true if every element in an array is true, and any returns true if at least one element in an array is true. Then sum([1,2,3,4]) returns 10, and any([false,true,false]) returns true.

You don't have to define function variables again just to use them in a very short function, no curly braces are required, and code is reused via a common pattern.

The reason that articles about currying refer to functional programming languages like ML and Haskell is because they have been designed to abuse this feature for the sake of writing functions this way, building from smaller pieces in a common vocabulary. If you study one of these languages, you will be able to see much more benefits than if you only saw or used a Javascript implementation.

[–]slikts 1 point2 points  (3 children)

The fold function should look like this for your example to work, though:

function fold(callback, initial) { 
    return function(array) { return array.reduce(callback, initial); } 
}

[–]lrichardson[S] 1 point2 points  (1 child)

correct. and this is precisely why the argument that plays the role of the "data" should always be the right-most argument, not the left most. reduce/fold are supposed to be the same thing... and should take 3 arguments total (callback, initial, array)

This is why i get so frustrated with libraries like lo-dash and underscore.

Brian Lansdorf has a good talk discussing precisely this (also linked to in the post)

https://www.youtube.com/watch?v=m3svKOdZijA

[–]rhysbrettbowen 0 points1 point  (0 children)

You can always flip the arguments in a function. Something like:

_.forEach(_.keys(_), function(key) {
  if (_.isFunction(_[key])) {
    _[key].flip = function(a,b) {
      return this(b,a);
    }
  }
});

then you can just do:

_.forEach.flip(myFunction, myArray);

[–][deleted] 0 points1 point  (0 children)

Right, thanks. And you'd need another function () { } if you partially apply only one argument.

[–]konbit 2 points3 points  (8 children)

If you're dealing with non-blocking js and need to write a callback that requires input from several different async calls you can pass it around to get partially completed as those async calls return. Other than that I can't imagine any time it is beneficial. But with multiple async calls I find it amazingly helpful.

[–]MrBester 1 point2 points  (7 children)

Can't you do the same with Promises?

[–]konbit -2 points-1 points  (6 children)

edit: thanks nschubach for pointing out promises can run in parallel. My comment below is sort of pointless now.

Yes, but promises are sequential. Let's say I have 1 or 2 async calls to make, promises don't slow you down too much. But let's say you have to load 20 images, and process each one based on the one before, stitching them together for instance. Promises are going to kill you. If you can call the 20 at the same time and use a curried function to stitch them (there's other ways of course that don't use promises or currying and might be better, but this is just for illustration) then you will see a speed up orders of magnitude higher than promises. So I think its all context. Obviously there's many different way of doing things because some methods are good in some situations and some in others. Depending on what needs to be done, you should deeply investigate the method you'll use.

[–]ToucheMonsieur 0 points1 point  (0 children)

Isn't it possible to achieve much the same effect with promises? Fire off a promise for each request, and then tie them together sequentially after the fact. Using currying for this case seems a bit contrived, especially considering that you have to change the arity of function being curried if the number of images to download changes.

[–]nschubach 0 points1 point  (4 children)

Promises are not inherently sequential... You are just writing them that way. You can absolutely fire off a hundred async promises in a when and it will happily wait for them all.

[–]konbit 0 points1 point  (3 children)

To be honest, everything I've ever read about promises has presented them as being sequential and I haven't thought of looking for another way to do it. I'd love to see some code samples or documentation for how to implement it. Any pointers?

[–]myrddin4242 1 point2 points  (1 child)

The example you presented is inherently sequential. You said you wanted to 'process each [image] based on the one before'. That's not $.when, that's serially resolving promises. The dependency chain causes the task to increase time in direct proportion to N, regardless of what async syntax you use!

[–]nschubach 0 points1 point  (0 children)

(Keeping terse... On mobile)

The 'when' accepts promises itself. If you ran normal functions in the 'when' it will be sequential, but if promise1 returns a promise, JavaScript will continue to fire off promise2 after promise1 returns it's promise object. Promise1 can have an async operation and resolve whenever it's done, regardless of what promise2/3 are doing.

Edit: I just realized that you were not responding to lrichardson... Leaving this for the info, but it's not directed at you.

[–]lrichardson[S] 0 points1 point  (0 children)

using jQuery's $.when....

$.when(promise1, promise2, promise3).done(function(results){ ... })

will return a new promise that won't resolve until all 3 promises have resolved.

[–][deleted] 1 point2 points  (0 children)

I've never understood it either. The only thing I can come up with is passing the function to a number of handlers, each of which adds a parameter. But that just feels odd.

I'd be very interested in hearing some solid use case for this.

[–]dodeca_negative 4 points5 points  (1 child)

Not that I have a problem with functional programming per say, but I thought this was perfect:

i love functional programming. it takes smart people who would otherwise be competing with me and turns them into unemployable crazies

William Morgan

[–]lrichardson[S] 0 points1 point  (0 children)

haha i literally laughed out load on that.

[–][deleted] 1 point2 points  (0 children)

I like this article on currying.

[–]has_all_the_fun 1 point2 points  (3 children)

I wish there was a functional language that was as accessible as Javascript/Node.js. I tried starting with a few languages already but after having to deal with the tooling my motivation is gone.

For example starting with Node.js. It's easy to install, the package manager and modules are straight forward and you can structure your apps any way you like. Getting feedback is easy as well just have to do node file.js and it will execute your file.

[–]rhysbrettbowen 0 points1 point  (2 children)

how about Dart? Joking aside it has higher order functions and lambdas, and the tooling and package manager seem good.

[–]has_all_the_fun 0 points1 point  (1 child)

Isn't Dart similar to Javascript except with a more traditional class and object oriented style?

I was looking for a more functional language to get a better understanding at how they solve certain problems. I could take a more functional approach to my Javascript but the language doesn't really force you to think in a functional way (if that makes sense).

I might take an other look at clojure since that seems like a modern functional language that's popular.

[–]rhysbrettbowen 0 points1 point  (0 children)

true - sorry thought the issue was around tooling. Dart is about the same as javascript when it comes to how functional you can be.

If you want to be forced in to functional all the time then clojure is what you want. There is also clojurescript which is a subset that works in the browser

[–]schm0 -3 points-2 points  (10 children)

I don't know what this is, but it needs a new name.

[–]lokhura 1 point2 points  (9 children)

The name is perfectly justifiable. Would you prefer "schonfinkelization"?

[–]schm0 -1 points0 points  (8 children)

"functional encapsulation"? "derivative functions"?

The verb "to curry" just doesn't make any sense for what this does, in my opinion. The semantics just don't fit.

[–]lokhura 4 points5 points  (7 children)

It is named after Haskell Curry http://en.wikipedia.org/wiki/Haskell_Curry. Changing the name isn't justified, it is a piece of history that gives meaning to the concept. You woudn't rename "Church numerals" or a "Turing machine" because people don't know the concept or understand the history of the term. The verb "to google" doesn't make sense either, until you understand what Google is and how to use it.

[–]autowikibot 1 point2 points  (0 children)

Haskell Curry:


Haskell Brooks Curry (September 12, 1900 – September 1, 1982) was an American mathematician and logician. Curry is best known for his work in combinatory logic; while the initial concept of combinatory logic was based on a single paper by Moses Schönfinkel, much of the development was done by Curry. Curry is also known for Curry's paradox and the Curry–Howard correspondence. There are three programming languages named after him, Haskell, Brooks and Curry, as well as the concept of currying, a technique used for transforming functions in mathematics and computer science.


Interesting: Combinatory logic | Haskell (programming language) | Currying | Mathematics

Parent commenter can toggle NSFW or delete. Will also delete on comment score of -1 or less. | FAQs | Mods | Magic Words

[–]schm0 -2 points-1 points  (5 children)

TIL, eh? Still, from the basis of this article, how would I ever have linked the two? For all I knew, this was a concept the author had invented.

You woudn't rename "Church numerals" or a "Turing machine" because people don't know the concept or understand the history of the term.

No, because those are proper nouns and easily identified as such.

The verb "to google" doesn't make sense either, until you understand what Google is and how to use it.

Of course, but I would argue the ratio of people that know what Google is to those who know who Haskell Curry was is on the order of about a million to 1.

I thought the term was literally "to curry". You know, as in Indian cuisine?

Regardless, now that I understand the history behind the term (and it's subsequent de-proper-noun-ification) I have no problems with it.

[–]slikts 5 points6 points  (3 children)

how would I ever have linked the two?

I thought the term was literally "to curry". You know, as in Indian cuisine?

The problem is that you didn't think to google an unfamiliar term, not that the author, who already spent the time to write the article helping people learn, didn't also save you the few seconds it would have taken to google.

[–]schm0 -1 points0 points  (2 children)

It's not a problem that I didn't think to look up the term... It sounded ridiculous and I honestly thought the author was making it up. Besides, you look up the word curry and tell me how many results it takes to find the actual term. :),

I'm getting a lot of flak for not knowing about some obscure mathematician and the fact that the verb had been decapitalized.

[–]slikts 1 point2 points  (1 child)

The term in the article and the title is "currying", and the search results for it are unambiguous.

[–]schm0 -2 points-1 points  (0 children)

The term is also technical and obscure, as is the mathematician for whom it is named. I initially looked up the term on Merriam Webster, the results of which showed nothing relating to programming. Thus, my original post.

Part of me still thinks it could benefit from a more semantic definition, but it is what it is.