What is the advantage of currying?
programmers.stackexchange.com
programmers.stackexchange.com
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 respectively1. 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.
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.
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.
In particular, it naturally splits apart the different function calls. So you can look at the parts separately: L.intercalate "\n", cut (b'-b+1), map toChar, elems arr. Now you have a nice little pipeline.
Perhaps to somebody without Haskell experience, the version with parentheses would be easier to understand:
L.intercalate "\n" (cut (b'-b+1) (map toChar (elems arr)))
However, in general, I find the $ version easier to follow.I also think that this version is better than the same code broken up into arbitrary temporary variables. The pipeline is short and clear; adding temporary bindings would just give me more things to keep in my mind at the same time.
One way to think about this is that the $ is very similar to the | in bash, just backwards. So in a bash-like pseudocode, this is something like:
elems arr | map toChar | cut (b' - b+1) | L.intercalate "\n"
Hopefully that clarifies the structure of the code and why that structure is actually very reasonable.Basically, my point is that the given code is clear and simple; chances are you find it hard to read because Haskell is somewhat foreign and not because the given code is particularly complicated or obfuscated. In fact, I think this way of writing the code is clearer than what you would get in most other languages because it forms a very clear sequence of transformations on the input.
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.
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.
The main benefit is syntactic ease of partial application.
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).
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.
instance (PrintfArg a, PrintfType r) => PrintfType (a -> r) where instance (PrintfArg a, PrintfType r) => PrintfType (a -> r) where
spr fmts args = \ a -> spr fmts (toUPrintf a : args)
And spr is a polymorphic function of the type: spr :: String -> [UPrintf] -> t
Essentially the way this works is that it recursively conses up a list of the arguments, calling toUPrintf on each.Not that currying is a bad thing, of course. For the right functional combinators (map, reduce, etc.) currying can be put to very elegant use.
As you'd suspect from that lead-in, currying is one of those things. Explaining how it works is easy in a blog post, explaining why it is interesting is hard to do without being A: trivial or B: gibberish if you don't already know Haskell fairly well. Both approaches are taken in the StackOverflow there.
While it does mean you lose default and named args, it turns out to hurt less than you'd think, because the whole runtime and library is set up around functions without named args. I'm not sure exactly why, but when you can break things down into such smaller grained functions it seems to matter less. Positional is handled by a variety of functions that can reorder arguments, most commonly "flip" which switches the order of the first and second arguments, and while that is used and idiomatic it's probably used less than you'd think.
I can assure you it gets used a lot in idiomatic Haskell.
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 :-)
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.
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.
:)
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.
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.49.1... (also, full paper .ps at author's web page)
Note: this was written purely for fun, don't use it in a real project!
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 (addition); "Currying" at the Haskell Wiki http://www.haskell.org/haskellwiki/Currying (division); "Currying" at Wikipedia http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_... (division); "Currying" at c2 wiki http://c2.com/cgi/wiki?CurryingSchonfinkelling (addition, multiplication); PEP 0309 for adding curry to Python 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/ 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.
It's kind of weird because the more arguments your function has, the more useful partial application is, and the less likely the curried form is going to work without reordering.
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.
With add they do the same but with say divide they do different things (both useful).
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.
> 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λ: (/) 2 4
0.5
λ: flip (/) 2 4
2.0