For instance, my company writes a lot of code in a proprietary language and the other day I was writing a function to generate random strings, given a length and an "alphabet" string from which to choose characters.
I chose the ordering:
randomString alphabet length = ...
so that if partial function application were added to the language, one could simply write the functions randomHex and randomBase32 as: randomHex = randomString "0123456789ABCDEF"
randomBase32 = randomString "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
The alternative ordering would allow me to easily write functions that generate fixed length strings and take their alphabets as inputs: random10Char = randomString 10
random4Char = randomString 4
This ordering is much less useful in general, so I chose to make the alphabet the first parameter.On a side note, our language also has some time series extensions for dataflow programming. There's an API for efficiently adding new data flows based on something similar to template specialization, but the API is unwieldy and the source of much confusion. So, I wrote a wrapper API that uses reflection to expose the same functionality as partial function application / Curried functions over time series.
Oddly though, when writing haskell code, I don't worry about it much. Once I find myself needing to `flip` a function before using it, I have determined experimentally that the original parameter order I picked was not the best one, and I then go change the function, and let the type checker walk me through fixing any necessary call sites (which also verifies if the new parameter order is better or not).
It seems like it would be easy enough to have a special "placeholder" keyword that means "these parameters will be the parameters of the curried function". To take his example:
var jp = formatNames2('John', 'Paul');
That might be written like this instead: var jp = formatNames2('John', 'Paul', _);
And then if you want to curry the second parameter instead of the third, it's easy: var jp = formatNames2('John', _, 'Jones');
Or maybe they do and I just haven't heard of it? def randomString(alphabet, length):
....
randomHex = partialApply(randomString, alphabet="0123456789ABCDEF")
randomBase32 = partialApply(randomString, "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567")
random10Char = partialApply(randomString, length=10)
random4Char = partialApply(randomString, length=4)
randomHexByte = partialApply(randomString, "0123456789ABCDEF", 2)
Comes in handy occasionally. var getIncompleteTaskSummaries = function(membername) {
return fetchData().then(function(data) {
var incompleteTasks = [];
for (i = 0; i < data.tasks.length; ++i) {
var task = data.tasks[i];
if (task.username == membername && !task.complete) {
incompleteTasks.push({id: task.id, dueDate: task.dueDate, title: task.title, priority: task.priority});
}
}
incompleteTasks.sort(function(a, b) {
return a.getTime() - b.getTime();
});
return incompleteTasks;
});
}
?Apologies if that's wrong, i barely know JavaScript.
That code is not so great, and a bit '90s, but it's not appalling. The horrifically verbose non-currying code in the article isn't something i see any need to write. It looks like an outrageous strawman to me.
My code here could definitely improved with some functional idioms for the looping, picking, and sorting, but i wouldn't reach for currying here.
The article really didn't get into the fact that these blocks of code that were listed inline would ideally represent reusable functions. That these functions would best be defined separately and only included by reference would have cluttered the article, but leaving them out does make it feel a bit like a strawman, I agree.
The breakdown of a task into these smaller functions is something I discussed more fully in the previous article: http://fr.umio.us/why-ramda/
(defn get-imcomplete-task-summaries [membername]
(.then (fetch-data)
(fn [data]
(sort-by :time
(for [task (:tasks data)
:when (= membername (:username task))
:when (not (:complete task))]
task ;; immutable, no need to copy
)))))
It makes me a little sad that functional programming has come to mean map/reduce/filter for lots of people, rather than avoiding mutation which is far more interesting.Readability is in the eye of the beholder. A tidy functional equivalent might look something like this (in a made-up syntax with typical functional idioms):
getIncompleteTaskSummaries membername =
fetchData
>>> tasks
>>> filter (task => username task == membername and not complete task)
>>> map (subsetkeys ["id", "dueDate", "title", "priority"])
>>> sortwithkeyfn getTime
Compare that with the explicit loops and tests above: var getIncompleteTaskSummaries = function(membername) {
return fetchData().then(function(data) {
var incompleteTasks = [];
for (i = 0; i < data.tasks.length; ++i) {
var task = data.tasks[i];
if (task.username == membername && !task.complete) {
incompleteTasks.push({id: task.id, dueDate: task.dueDate, title: task.title, priority: task.priority});
}
}
incompleteTasks.sort(function(a, b) {
return a.getTime() - b.getTime();
});
return incompleteTasks;
});
}
In practice, functions like filter, map, subsetkeys and sortwithkeyfn would probably be in your standard library and immediately familiar to anyone used to programming in such a language, so the only interesting details are the interesting details: which tasks you want to pick out, how you want to summarise them, and how you want the results ordered. Depending on what else is going on, you might even extract some or all of those three details into named one-liner functions to make the main algorithm more self-documenting and/or to allow those concepts to be reused elsewhere.The functional version as shown reduces 10 substantial lines with a lot of temporary variables and deep nesting to 6 total lines that each have a clear, self-contained purpose and that collectively systematically transform your input to your output. To my eyes, that style is far more readable and maintainable than manually reinventing fundamental algorithms like filter and map and camouflaging the interesting details within three or four levels of context.
Edited to add: Often the thing that makes functional style awkward is when a language that wasn’t designed with that style in mind adopts some of the useful concepts but without the elegant syntax and idioms to match. For example, we have somewhat unwieldy notation for defining quick local functions in JavaScript, lambdas that work as long as you can do everything on one line in Python, and the horrific lambda expression notation in modern C++. But I don’t think it’s helpful to conflate this with functional programming style itself, any more than it’s helpful to conflate Java’s verbosity with static type systems.
var result = somefunc(a,b) // object var otherResult = somefunc(a) // function
It gets even more confusing if overloading of function names for different parameters or different number of parameters is allowed.
So elegant: maybe. Readable: no. Depends on the programming language.
In a previous article (http://fr.umio.us/why-ramda/) I discuss more thoroughly how I would tend to use this currying, namely to build up collections of useful functions, often in points-free style, so that major parts of the application would end up as (ideally well-named) functions, each which serve as pipelines of these smaller functions, passing data through the system.
I do find this significantly more readable, but _de gustibus non est disputandum_.
Basically, it seems to me like trying to fix something that isn't broken.
The purpose of currying is to improve reuse and chaining of functions, resulting in easier to read and more elegant code.
I think this, along with the whole article, is the best explanation of currying I've seen on the whole damn internet.
http://www.uncarved.com/blog/not_currying.mrk
Which the author freely admits:
(Some will insist that what we're doing is more properly called "partial application", and that "currying" should be reserved for the cases where the resulting functions take one parameter, each resolving to a separate new function until all the required parameters have been supplied. They can please feel free to keep on insisting.)
-- all morally identical
a -> b -> c -> d
a -> (b -> c -> d)
a -> (b -> (c -> d))
(a, b) -> c -> d
(a, b, c) -> d
((a, b), c) -> d
(a, (b, c)) -> d
However, so long as you have parameter order (we're not allowed to commute our tuples, just reassociate nested tuples like ((a, b), c) <-> (a, (b, c)) and so on) then flip still morally works flip (someFn :: (a, b, c) -> d)
:: (b, a, c) -> d
:: (b, a) -> c -> d
:: b -> a -> (c -> d)
The same story holds for partial evaluation. Of course, there have to be far more edge cases to handle all this tuple twiddling.---
Really, I think it's pretty meaningful to blur the distinction between "curry (once)" and "curry repeatedly along with tuple reassociation". The later forms an equivalence class of function types which all have the same application behavior.
I feel that although the distinction can be very important, it's much less so for Javascript. And the implementation in Ramda can be used that way any time you choose:
var total = reduce(add)(0); // or
var sum = reduce(add)(0)(numbers)
works just as well in Ramda as var total = reduce(add, 0); // or
var sum = reduce(add, 0, numbers)
So, as I said, feel free to keep on insisting. :-) var jp = function(last){
return formatNames2('John', 'Paul', last);
} var jp = function(last) {
return formatNames2('John', 'Paul', last);
};
var je = function(last) {
return formatNames2('James', 'Earl', last);
};
var lh = function(last) {
return formatNames2('Lee', 'Harvey', last);
};
var c = function(middle, last) {
return formatNames('Clarabelle', middle, last);
};
But I find this cleaner: var jp = formatNames2('John', 'Paul'};
var je = formatNames2('James', 'Earl'};
var lh = formatNames2('Lee', 'Harvey'};
var c = formatNames('Clarabelle'};No, because I use Array.prototype.filter(), Array.prototype.map(), and Array.prototype.reduce() to accomplish these things...
Extreme point free style does not work in javascript, AT ALL!!!! Two reasons:
1) Find the bug: the table sort is glitchy. Is the bug in this suspicious line, or somewhere else? (Real line of code in a codebase I inherited, and yes there is a bug in it)
var sorted = rows.sort(_.unsplat(_.pipeline(
_.partial(_.map, _, accessor),
_.splat(comparator))));
2) I use React, so I can get away with a lot of really functional stuff since React is well suited for functional javascript. React is a great functional abstraction, but under the abstraction is imperative code. Imperative code means you need a debugger. When you write in a point free style, there's nowhere to place a breakpoint!On the other side, I tend to work with a few well-tested functions over and over and end up with fewer problems to debug when I work in a functional paradigm, points-free or not.
On rare occasions, when I need to debug something that is difficult because it's points-free I simply add some explicit parameters, either temporarily to enable debugging or permanently.
Points-free is nice, but should never be an overriding goal.
The code is a little more confusing at first glance. The developers who replaced the code with curried functions didn't inform the whole team what they were doing. There were a lot of wtfs until they clarified. Now we can read it, and I know I'll be looking for places for partial applications.
As Currying and functional programming a popular thing now, I was thinking what my current codebase would look like in C# if I were writing code in a more functional way.
So, obviously C# isn't a functional languageat all but using Func<T>, and maybe some delegates would enable this easily.
I'm not sure this would turn my code to more elegant or readable.
What would I benefit from ?
The .NET platform of course has F#, which is a dedicated functional language. Some day I'll spend some time learning this one... perhaps.
I think that using the .bind() method on functions is the right approach. It will lead to less surprising behaviour in the context of javascript.
However, I find lambdas with the extra parameters repeated more readable than partial application.