
Practical functional programming in JavaScript - walrus
http://extralogical.net/projects/udon/
======
peteretep
> Currying is the process of converting a function of arity n into a nested
> set of functions with arity 1, i.e. making it partially applicable

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?

~~~
peteretep
Also it seems a bit weird to have 'any' and 'filter' without having 'first'.

~~~
ostso
Not really -- "any" and "filter" are total functions, but "first" of an empty
list is undefined.

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.

~~~
ionfish
It seemed unnecessary, yes, although I suppose there are possibly some
circumstances where one might want a `first` function—for example if one were
folding over a list of lists.

~~~
286c8cb04bda
There are an infinite number of circumstances where one would want 'first'.

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.

~~~
dllthomas
In most cases the "a[0]" approach works, however. The set of circumstances
where you want "first" as a proper function is limited to those cases where
you need to pass it into some higher order function (which is still infinite,
granted, but it's not 'every time we'd want "car"').

------
Swizec
As both a functional and a javascript programmer - I don't see the point of
the curry function. I understand currying is great, I even use it a lot, but I
don't see the benefit of converting a "normal" function to a curried one.

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)

~~~
tiglionabbit
I'm with you on the currying thing. The ability to curry functions doesn't
enable you to do anything you couldn't already do better and with more
flexibility by writing the full anonymous function.

Their example breaks down the moment your argument order matters:
<https://gist.github.com/3052264>

~~~
Peaker
They seem to simply be missing flip.

    
    
      // 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)

~~~
ionfish
Yes, although there is one subtlety here: should `flip` return a curried
function, or an uncurried function? This isn't an issue in Haskell since it
only has unary functions.

~~~
Peaker
Haskell has tuples, so it could use an:

    
    
      (a, b) -> c
    

representation. If the uniform/canonical way to use functions is defined to be
curried, then flip can simply return them curried.

~~~
masklinn
> Haskell has tuples, so it could use an:

Which it does:

    
    
        curry :: ((a, b) -> c) -> a -> b -> c
    
        uncurry :: (a -> b -> c) -> (a, b) -> c

------
masklinn
Why would I go with Udon (eager, functional) rather than underscore (also
eager and functional, but more popular) or wu.js (lazy & functional)?

~~~
ionfish
You probably shouldn't. :)

------
egonschiele
Looks awesome, mainly because all the function names tie up with Haskell, but
what's the difference between this and underscore.js?

Also, you might be interested in Roy: <http://roy.brianmckenna.org>

~~~
ionfish
It has a few more functions that operate on lists, but it's missing a lot of
the general utility functions that Underscore has.

Roy looks interesting, thanks for the link.

------
clux
I'm in the process of writing my a functional utility library myself, and
having thought about these things for a while, I think letting everyone curry
things themselves make things less intelligent.

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>

~~~
ionfish
> having to write Udon.curry everywhere sort of takes away from that
> cleanliness you are trying to recreate.

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.

------
mappu
Is it standard practice in other languages / libraries to have the function
argument first and the data argument second, in e.g. map and filter?

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).

~~~
walrus
Putting the data argument second is nice when combined with currying. For
example:

    
    
      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]

------
GeZe
If you are interested in this you might want to check out
<http://gkz.github.com/prelude-ls/> \- it has almost all the functions
included in Udon as well as about 60 more based off of Haskell's Prelude
module.

~~~
ionfish
That's very cool, although you have to use another dialect of JavaScript if
you want to modify the source code, with all the disadvantages that entails.

~~~
jjm
True, but taking that aside and focusing on practicality, both underscorejs
and Preludejs together provide one heck of a toolbox. I really enjoy
functional programming a great deal and have been using it every which place I
can the last several years. I totally understand that this is your take on the
subject matter and so far so good, though the docs and usage for me are
strange. If you have the goal of mass adoption you'll need to convince people
like me why it needs adding to the toolbox.

~~~
ionfish
I don't think one can ignore that and also focus on practicality. Using these
JS dialects _is_ a practical issue. Learning them and remembering how they
work imposes a certain amount of overhead, albeit a reasonably small one. Of
greater concern is maintaining projects written in these dialects: what if the
support around key parts of your toolchain goes away? Of course they're open
source, so you can maintain them yourself—but that may be a lot of work, and
will rarely be the highest priority. Ultimately it may be more effort than
it's worth, even if it's a lot more enjoyable to write than vanilla
JavaScript. I'm not saying that this will always be the case, but it's an
issue that does need to be addressed before jumping in and using them on a
major project.

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.

~~~
jjm
It's an issue I see when things go public. Public then mainstream. As such
mainstream users mean mainstream docs. So my evaluation was in those eyes. The
most important thing to gain is refinement that can be learned for the next
lib you may or may not start/contribute to.

------
tikhonj
I'd probably throw in concatMap, head, tail and the various scan functions for
lists. Maybe init and last as well, although I never really use them.

As far as functions go, uncurry would be neat and create a nice symmetry along
with curry.

~~~
ionfish
Patches for these would be welcome; I did mean to add them, but I got
distracted by other projects, and then by my PhD.

------
sodelate
i don't see any advantage of using it

