7 ms·
What is the advantage of currying?
- huhtenberg 14y agoIt'd be nice to have a form of currying in C/C++ as applied to function pointers. Specifically, if I have int foo(void * bar, int baz); then I should be able to use foo(, 10) where int (*)(void *) is expected. Taking it beyond constant-based specialization would obviously require a support for closures, but I think it's a safe bet that the standard C will get it sooner rather than later.
- Someone 14y agoSafe bet? For C, I am not sure of that. They would want to stay close to the metal, and have true function pointers. Creating those on the fly means having them in the data segment (or some horrendous OS-specific and likely slow hack), and that is at odds with data execution prevention. C++ already has them, sort of. Templates accept 'anything that you can put () behind'. That includes function pointers and operator() overloads.
- CJefferson 14y agoIn C++11, you can write bind(f,_1,10). Not quite as neat, but not bad.
- huhtenberg 14y agoA lot of things are possible with C++, but they are universally just that - "not quite as neat". :)
- jacquesm 14y agoI read all those answers and I'm either not getting it or there really is something missing there. Isn't the big advantage that when you use currying that all functions have an arity of '1'? That means no more messing with varargs, named args (on the calling side), positional args, defaults and so on, every function takes one argument and one argument only, currying is then used to bypass the limitations of having only one argument to work with.
- Peaker 14y agoThe lack of named args is seen as a disadvantage. Varargs are modeled with Maybe params and such. The main benefit is syntactic ease of partial application.
- rwmj 14y agoIn a traditionally compiled language, currying doesn't provide varargs: the compiler still has to know how many parameters a function takes before it can be called. You cannot write `printf "%d" 1' expecting that at runtime printf is going to parse the string and read further arguments, because the compiler wouldn't know when printf can be called. OCaml famously (or notoriously) hacks this knowledge into the compiler, so the compiler knows about format strings and parses them. This is nicely typesafe, but means you cannot use varargs in your own functions, and there are odd restrictions on the format string. (You can use the camlp4 preprocessor, or lists-as-parameters, to get around this).
- guard-of-terra 14y ago"the compiler still has to know how many parameters a function takes before it can be called" I guess it's better viewed as: type system has to figure out whether a consecutive currying/calling will return a scalar/function of zero arguments.
- chongli 14y agoHaskell has printf without using lists-as-parameters. It accomplishes this by doing some very clever type-level trickery. The key idea is in the recursive definition of this instance of PrintfType: instance (PrintfArg a, PrintfType r) => PrintfType (a -> r) where
- philsnow 14y agoYour snippet got cut off, care to paste the rest? I'm guessing it works by popping the format string and the first operand off the args, and then finding the first formatting escape in the format string and formatting it, then recurse.
- manojlds 14y agoThe OP had not understood what currying is, and went about asking the question. Was expecting a more well thought question. Wonder why it was upvoted. The question itself is poor.
- Kiro 14y agoThe answers are worse.
- tikhonj 14y agoWhat's wrong with the answers?
- thisone 14y agoI'm betting 99% this question is coming from someone taking the coursera "Programming Languages" course, since this week covered currying (in SML/NJ), amongst other things. The question is poor because it specifically gives such a simple example of currying. You can't understand certain concepts without understanding when they are used, and when they aren't. If the OP had instead said "I don't understand why List.foldl is curried instead of just accepting a tuple." Then you'd see a more productive discussion. Perhaps touching on the differences between functional language implementations. As it is, since the question isn't formulated well, the answers are all over the place.
- deleted 14y ago[deleted]
- guard-of-terra 14y agoCurrying is a functional approach. But there is an object-oriented approach that works even better: You have a Function add object that has methods bindWith1(x) and bindWith2(y) both returning a function of one argument. With add they do the same but with say divide they do different things (both useful).
- michaelfeathers 14y agoYes, you can do that, but to me it's not as nice as having as syntax that makes it easy and natural. This is where the ML-derived languages like OCaml, F# and Haskell beat other functional languages, in my opinion. You can argue that it's nice to be able to choose the argument to bind, but I think that's actually a bad feature. It gets rid of the design pressure to pick an order of arguments that maximizes easy composition.
- guard-of-terra 14y agoMy experience with clojure/haskell tells me that order of arguments of common functions feels horribly wrong sometimes.
- michaelfeathers 14y agoI guess there are no guarantees. Which ones are you thinking of in Haskell? There it seems to matter more.
- guard-of-terra 14y agoI always seem to struggle with array/list indexing functions.
- crntaylor 14y agoLike these? > let lst = [1,2,3] > lst!!0 1 > lst!!1 2 > let arr = listArray (0,2) [1,2,3] > arr!0 1 > arr!2 2 I don't see how it would be particularly helpful to have the arguments to the indexing functions the other way around, but in case you really like the index coming before the list/array, you can always do > (!0) arr 1 > (!!1) lst 2
- michaelfeathers 14y agoI don't think that people really see the advantage of currying until they work in an ML-derived language like Haskell. The syntax is tuned to make it easy and you get very nice design affordances. In languages like Scala, C#, etc., currying was an afterthought and it shows. I actually think it's a shame that the Lisps make currying unnatural also. Yes, they have homoiconicity, but it's a sad tradeoff.
- deleted 14y ago[deleted]
- dschiptsov 14y agoYou can write fancy code in Haskell and then write long, narcissistic blog posts.) Seriously, it is all about closures - you could capture (and delay) the computation, like creating a closure (a function with its parameters) and then actually execute the code when some other conditions were meet. Currying allows you to execute all steps but last one, for example, so you will have a returned function to call whenever you wish.
- groue 14y agoAnother perspective of currying, from a guy that is not versed in functional programming. I have written an expression evaluation engine whose internal implementation only manipulates functions that have a single argument. Merely value transformers. It used to only interpret expressions like `f(x)`, `g(f(x))`. Later, functions were able to return other functions, and `f(x)(y)` was allowed. However, this last expression really looks like it would be better written `f(x,y)`. Why force the user to use a convoluted curried syntax such as `f(x)(y)` for his two-parameter function? So the `f(x,y)` form has been added as a mere syntactic sugar. However the guts of the engine are still made of single-argument functions. That can get curried. So currying is not only a tool for the end-user. It's also a tool for the language implementor :-)
- eliben 14y agoThis mainly makes me lament the fragmentation of the Stack Exchange network. This question, in particular, should have been on Stack Overflow. IMHO this fragmentation hurts the community. Very much.
- crntaylor 14y agoHere's a line of code taken from a (Haskell) Game of Life simulation I was writing just a couple of days ago [0]: showGrid (Grid _ ((_,b),(_,b')) arr) = L.intercalate "\n" $ cut (b'-b+1) $ map toChar $ elems arr This is the full code to convert a state of the board to a string, ready to be printed to stdout. It consists of a chain of four function applications, which respectively 1. Get the elements of the array as a list (elems) 2. Convert each element to a char (map toChar ... toChar is defined elsewhere - it's also a one-liner). 3. Cut the list into sublists of the correct length (cut (b'-b+1)). 4. Join the lists together into a single string, separating them with newlines (L.intercalate "\n"). Three of the four functions are curried. I contend that without currying by default, it would take more resources (in terms of lines, characters and mental effort) to write this function. [0] https://github.com/chris-taylor/Life https://github.com/chris-taylor/Life
- taeric 14y agoOf course... I think many would say that your savings in resources came at the expense of readability. Basically, I think this falls dangerously close to Duff's device in the argument space of currying.
- crntaylor 14y agoYour first point is fair. Of course, 'readability' is extremely subjective. It should always be judged in terms of the intended audience for the code - we'd have to ask a Haskell programmer to be sure. Your second point I disagree with completely. Duff's device is non-idiomatic C that relies on oddities of C syntax (fall-through of cases in a switch statement, and the ability to jump into the middle of a loop). My code is reasonably idiomatic Haskell.
- taeric 14y agoApologies, I should have made the second point more on the humor side than not. I should also stress that I don't think this being somewhat difficult to read is really bad. Just saying that I would expect a lot of folks to balk at it.
- markov_twain 14y agoWhy has arithmetic become the universal example of currying and partial function application? Examples: "Currying", Section 9.3 of Programming in Scala (addition); Ruby 1.9.3 documentation for Proc#curry http://www.ruby-doc.org/core-1.9.3/Proc.html#method-i-curry http://www.ruby-doc.org/core-1.9.3/Proc.html#method-i-curry (addition); "Currying" at the Haskell Wiki http://www.haskell.org/haskellwiki/Currying http://www.haskell.org/haskellwiki/Currying (division); "Currying" at Wikipedia http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_... (division); "Currying" at c2 wiki http://c2.com/cgi/wiki?CurryingSchonfinkelling http://c2.com/cgi/wiki?CurryingSchonfinkelling (addition, multiplication); PEP 0309 for adding curry to Python http://www.python.org/dev/peps/pep-0309/ http://www.python.org/dev/peps/pep-0309/ (addition); this StackExchange post; etc. Surprisingly, searching for currying in JavaScript returns this John Resig post with actually useful examples: http://ejohn.org/blog/partial-functions-in-javascript/ http://ejohn.org/blog/partial-functions-in-javascript/ although they still have no advantage over doing partial application by just defining a new function. The only situation in which I've ever thought to myself "I know, I'll use curried functions," was in passing a set of data through a bunch of filters with different arities. To take an example from HN's front page today, say you want to take some map of key value pairs, grab all the keys, convert them to strings, reject duplicates, sort them alphabetically, and finally concatenate them separated by commas. Let's assume you have the following functions available (in pseudocode): keys(map) -> vector flatmap(func, vector) -> vector tostring(anything) -> string sort(sort-func, vector) -> vector compare-strings(string, string) -> first-is-greater, theyre-equal, or last-is-greater unique(compare-func, vector) -> vector concat(separator, vector) -> vector and assume you have some way of connecting a list of these filter functions together like pipes, where the output of each function becomes the input of the next: reduce(composing-func, list-of-filter-functions, initial-input) -> final-result Here, the composing-func takes two arguments: input, which is the output of the last iteration (or initial-input); and filter, which represents each function that will be applied in turn to produce some output. Notice that each filter function must take exactly one argument, which matches the return type of the previous filter-function in the pipeline. composing-func = (previous-result, filter) -> { apply(filter, previous-result) } Now looking at our available functions, we can use currying and partial function application to pre-fill-in some arguments needed so that their input and output types line up: list-of-filter-functions = [ flatmap(keys), map(tostring), unique(compare-strings), sort(compare-strings), concat(",") ] And actually, we're now done. All of our filter functions have been partially applied as a sort of initialization for a complicated pipeline. I'm guessing that currying and partial function application are useful in building parsers (like haskell & scala's parser combinators) but I don't know.
- egonschiele 14y agoAha, finally a place to show off my curry gem for Ruby! https://github.com/egonSchiele/Curry https://github.com/egonSchiele/Curry Note: this was written purely for fun, don't use it in a real project!
- jonjacky 14y ago"Fields in Physics are like Curried Functions, or Physics for Functional Programmers" - 1994 paper by Gary Leavens http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.49.1181 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.49.1... (also, full paper .ps at author's web page)
- virmundi 14y agoI've been reviewing OO patterns for my class. I've also studied Scala a bit in the last year. One thing currying seems to look like is a builder pattern for functional programming. I can start with a function that requires N number of different arguments. I can use currying to accumulate specific setting for the function over time. Eventually when I get everything actually required for the function, I can invoke it.