Taking the example from the original article, it would be more akin to:
// Implementation
function double(n) {
return n * 2;
}
// Declaration
[1,2,3,4,5].map(double)
=> [2,4,6,8,10] elements = [1,2,3,4];
doubledElements = doubleElements(elements)
Basically, if you see the words map, fold, reduce in your code, you are probably not as easy to understand as you'd like to think.Of course, in the cooking methaphor, I'm ok with mutating elements and just doing:
elements = [1,2,3,4];
doubleElements(elements);
This clearly has issues if multiple "cooks" are working with elements. But is ridiculously easy to intuit regardless. (Precisely because in real life so many things are changed by imperative commands.)But then you lose pureness, right? The whole point of using high-order functions is allowing you to be as declarative as mathematics, so you can just operate functions together.
Consider that in the first example, I only need to write the implementation for doubling a number n, while the `doubleElements` implementation is too specific, would throw the other half of the code back into imperative land.
I suppose I should have said that the doubleElements implementation would likely be that map one liner. (Though, it needn't be. One could exploit custom knowledge of the domain there to do crazy crap like memoize the calls.)
That make sense?
Yes, the first example uses pure functions, but I guess you're confusing pure functions with HOFs [1]. The point is only having to write the implementation to double one number, and extrapolating it by composition. Consider that in your example, for instance, you would need a `doubleHash` function for hashes, and so on.
That is, I'm fine with using both the pure and HO functions. I just think hiding the HOF ones behind a normal function call is usually a big win for readability.
So, to do the full example:
elements = [1,2,3,4]
doubledElements = doubleElements(elements)
function doubleElements(e) {
function double(n) { return n*2; }
return e.map(double);
}
Where I would assume the "reader" code would only have the first two lines. The rest would be behind the implementation layer. If the double function would be used elsewhere, no need to scope it to doubleElements. - given a pan
- given 3 eggs
- given a little of olive oil
then one executes orders : - add the oil in the pan
- break the eggs and add them in the pan
- cook the eggs fo 5 mins
- serve the food hot
so i guess one is never really doing either pure declarative of imperative cooking/programming ?I like the cookbook metaphore for programming.
So, don't get me wrong. I'm all for declarative actions. I just think the "purely declarative" approach that many languages try and impose is a useful aberration when you consider how the vast majority of "programming" is done.
For some reason, it seems we programmers are adamant that it must be one or the other. Consider all of the examples, either purely imperative or purely declarative. Why not both?