Practical functional programming in JavaScript
extralogical.net
extralogical.net
If a reader knows what the words in the description mean, then presumably they know what currying is...
Wouldn't it be better to have documentation that illuminated, rather than showed off your grasp of programming terms?
On the other hand, that also applies to foldl1 and {max,min}imum{,By}, so it's probably not the reason.
The reason is probably that in JavaScript you can just say a[0] to get the first element element of a.
In Lisp terms[1], 'first' is 'car', which, in conjunction with 'cdr'. With that combination recursive logic is regularly implemented.
[1] Some Lisps already include this alias.
I mean, when I need currying, I just write my code like that.
Everything else looks pretty awesome!
Have you looked at underscore (http://underscorejs.org/) a lot of the functionality seems to overlap (and it's what I've been using for a long time to make functional javascript a bit more palatable)
Their example breaks down the moment your argument order matters: https://gist.github.com/3052264
// Lets curry subtract instead of add
var subtract = Udon.curry(function(a, b) {
return a - b;
});
var five_minus = subtract(5);
var minus_five = Udon.flip(subtract)(5) (a, b) -> c
representation. If the uniform/canonical way to use functions is defined to be curried, then flip can simply return them curried.Which it does:
curry :: ((a, b) -> c) -> a -> b -> c
uncurry :: (a -> b -> c) -> (a, b) -> c Udon.flip = function(f) {
return function(x) {
if(arguments.length > 1) {
return f(arguments[1])(x);
}
return function(y) {
return f(y)(x);
};
};
}; subtract :: (Int, Int) -> Int
subtract (n, m) = n - m
fiveMinus = (curry subtract) 5
minusFive = ???
subtract' = \n m -> n - m
fiveMinus = \m -> 5 - m
minusFive = \m -> m - 5I'm pretty familiar with Underscore, just wasn't happy with a couple of the design decisions, otherwise I would have just used that. Udon actually came out of various hacky functional JS libraries that I'd written over the years, and part of the motivation was to pull those together into a clean and coherent codebase.
Also, you might be interested in Roy: http://roy.brianmckenna.org
Roy looks interesting, thanks for the link.
For example:
Udon.elem(2, [1, 2, 3]) === true;
As it stands this is simply an accessor for Array.prototype.indexOf. If people know how to use that, this alias is relatively useless unless you want to compose. And even then, you could always compose around the expression, or with a method on the prototype of the result (Number in this case).
However, it's very useful to have a curried version of it so that it can be used in filters:
[1,2,3,4,3,2].filter($.elem([2,4])); // [ 2, 4, 2 ]
This maintains your current javascript indexOf usage, but allows a higher order use that I think should be the default for this function.
If you want you JavaScript to look more like Haskell, then your way makes more sense, but having to write Udon.curry everywhere sort of takes away from that cleanliness you are trying to recreate. I prefer to not mess with existing semantics too much because of it. For reference, here's my library: https://github.com/clux/interlude#usage
This is true, and I considered your approach when writing functions like `elem`. There were two reasons for this. Firstly, I wanted to avoid introducing more closures than necessary. Secondly, I wanted to keep the source code reasonably transparent (if admittedly rather terse).
There is definitely a place for your approach, and it may even be the better one in practise. It's hard to say without writing large projects in both.
In usual PHP fashion, array_map and array_filter take arguments in different orders. From all the jQuery i write it seems more natural to put the function argument last ($.get, $().bind, etc).
doubler :: Num a => [a] -> [a]
doubler = map (2 *) var bigNumbers = Udon.curry(Udon.filter)(function (number) {
return number > 5;
});
bigNumbers([3, 1, 4, 1, 5, 9]); // [9]
bigNumbers([2, 7, 1, 8, 2, 8]); // [7, 8, 8] (set-result-to (do-this-to (do-that-to (do-the-other-thing-to (map map-function some-input-data)))))
If the order of arguments to map was reversed, your map function would be the only one messing up the right-to-left flow of your data./so not a functional programmer
Anyway, Udon was really just a personal library which I tidied up and documented in case it might be of use to somebody. I think this is generally good practise: it encourages one to write clean, maintainable code, some documentation, and a test suite with reasonable coverage. In principle one should always do these things, but somehow putting it somewhere public makes it more likely that they'll actually happen. I was actually quite surprised to see it on Hacker News today, since I first wrote it two years ago and last made any changes to the source code over a year ago.
In other words, I'm not exactly falling over myself to promote it to the wider world or make it fit people's needs other than my own. Patches to increase the functionality of the library or improve the documentation would of course be welcome, and several good suggestions have already been made on this thread. But I'm not too concerned about convincing people here or elsewhere that they should be using it. In fact, they probably shouldn't: as you and others have said, most or all of its functionality is provided by other libraries which are far more actively maintained (this is really just a corollary of my first point).
However, I would be interested in hearing what you think is strange about the documentation and usage.
It is a great contribution to the community and personally, regardless of my or other's personal technicalities.
As far as functions go, uncurry would be neat and create a nice symmetry along with curry.