Monday, November 17, 2008

Haskell Functions for Javascript


I've been doing a small Haskell project for the Uni and got really interested in this language and the Functional paradigm in general.

I suddenly felt like porting some of this cool functionality to Javascript.


I started by allowing functions to be curried. Here's a demo showing the script I made.

This is quite a fun way of making functions that derive from other functions.

Haskell functions

I then felt like porting Haskell's functions. Seemed doable considering Javascript has Higher Order Functions and we now can curry them.

I ported many Prelude's methods as well as Char methods.

Special features

Apart from currying, these functions can also work on strings, the same way as they do for lists (arrays). You don't need to worry about splitting(before) or joining(after). I added this because that's how Haskell's functions work.

These functions also work on maps/object/associative arrays. This might not be true for some functions where this was too complicated. This was the best adaptation of Haskell's Tuples that I could think of. A couple of functions like fst and snd don't have a concrete application for now.

In case I didn't make myself clear on this one, all the functions I made can be automatically curried. They're all contained in one namespace, that is, window.hs. I added a method called: that will import all the functions to the global namespace. The magic currying function is available as hs.curry.


Haskell's operators are regular functions. I did imitate this adding most operators as methods. The only problem is that to reference them, you need to use something like hs['+'] instead of hs.+ as one would like.

To defeat this, I made hs a function, it provides a small shortcut for these cases. As an example: hs['+'](1,2) == hs('+',1,2).

I think the second option does look better. These functions can also be curried. hs._ will work the same as hs, but inverting the (2) arguments.

I added the dot operator for function composition, it's quite a powerful function.


That's it, the script is licensed under BSD, check the demo and play with it!




Anonymous said...

I've implemented currying somewhat differently for my projects:

function curry()
   var args = jQuery.makeArray(arguments);
   var fn = args.shift();
   return function()
      return fn.apply(this, args.concat(jQuery.makeArray(arguments)));

// example:
function add(x,y) { return x + y; }
var add1 = curry(add, 1);
alert(add1(2)); // alerts "3"

Ariel Flesler said...

Hi Anton

That's pretty much the same I did. But yours can't be "chained".

For example:

add2 = add(2);
add5 = add2(3);

Curried functions also returned curried ones.

dual monitors said...

thanks! still learning this stuff

Ozgur said...

A little comment on chaining curried functions. Sorry if I get you wrong.

add2 = add(2);
add5 = add2(3);

By this example, assuming add is a function which takes to ints and returns an int originally, ie. a -> a -> a, this is not allowed in Haskell.

add x y = x + y
add2 = add 2 -- add2 is of type a->a now
add5 = add2 3 -- add5 is of type a now, having the value 5.


Ariel Flesler said...

Hi Ozgur
That's how it works in here as well. Try add(2)(3) in the console, you'll get 5.

Ozgur said...

You're right. Actually I tried with your console after posting the comment - dunno why :)

Your example is still ambigious though. At least the naming. If add2 is a function which adds 2 to any given number, namely a partially saturated add; I assume add5 is likely so.

It good to find out that the library is not faulty, but the example is (to some extend)

Nice work!

Ariel Flesler said...

Ohhh, you took the code from my comment. I wasn't sure where were you looking at.
I was explaining "chained" currying, it was just a theoretical example.

georgy7 said...

There is no window object in ecma-262-3. So it may not work in QtScript and probably Rhino. We'll have to do something like "window = this".

Ariel Flesler said...

You're right, will do that asap.

Ariel Flesler said...

Ok, that's done

georgy7 said...

Cool, but where have you uploaded the changes?

Ariel Flesler said...

Right, haven't made a formal release, I'm currently too busy.
Here are the changes.