Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #19964 > unrolled thread

New functional programming library: Eweda

Started byScott Sauyet <scott.sauyet@gmail.com>
First post2013-05-26 17:11 -0700
Last post2013-05-27 21:15 -0700
Articles 5 — 3 participants

Back to article view | Back to comp.lang.javascript


Contents

  New functional programming library: Eweda Scott Sauyet <scott.sauyet@gmail.com> - 2013-05-26 17:11 -0700
    Re: New functional programming library: Eweda Stefan Weiss <krewecherl@gmail.com> - 2013-05-28 03:00 +0200
      Re: New functional programming library: Eweda Scott Sauyet <scott.sauyet@gmail.com> - 2013-05-27 18:51 -0700
        Re: New functional programming library: Eweda "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2013-05-27 20:54 -0700
          Re: New functional programming library: Eweda Scott Sauyet <scott.sauyet@gmail.com> - 2013-05-27 21:15 -0700

#19964 — New functional programming library: Eweda

FromScott Sauyet <scott.sauyet@gmail.com>
Date2013-05-26 17:11 -0700
SubjectNew functional programming library: Eweda
Message-ID<5878382c-0503-44cd-b9cf-76befe26bcb7@s8g2000vbw.googlegroups.com>
I'm looking for feedback on a new functional programming library for
Javascript that I've been developing with a friend.  At the moment,
I'm mostly looking for critiques of the API; there is plenty to do on
the implementation, especially when it comes to performance, but I'm
feeling as though the API is coming into at least rough shape, and I'd
appreciate having more eyes on it.  But any feedback you have is
welcome.

The library is called "eweda", which is just a silly pun on "lambda".

The project is on Github, at

    <https://github.com/CrossEye/eweda>

and the library is in a single source file:

    <https://github.com/CrossEye/eweda/blob/master/eweda.js>

------------------------------

The API has a sizable overlap with Underscore [1] and LoDash [2].  But
its motivations are closer to allong.es [3] or Lemonad [4] or
Functional Javascript [5].  It's an attempt to do in Javascript
something more akin to normal functional programming, as would be
found in Haskell, ML, Scheme, or LISP.

The library's functions are available as properties on the main
function, `eweda`:

    var square = function(x) {return x * x;};
    var nbrs = eweda.range(1, 5); // => [1, 2, 3, 4]
    var squares = eweda.map(square, nbrs); // => [1, 4, 9, 16]

But they can be attached to any object, including the global object
via `eweda.installTo()`.  This will pollute the global namespace with
a number of functions, but might be the most likely expected use of
the library.  After that, you could just call

    var squares2 = map(square, range(1, 5)); // => [1, 4, 9, 16]

You might note something surprising here.  Even when it has the same
functions as Underscore/LoDash, its parameter order often differs.
This is intentional.  Underscore's API was built out of the native, OO-
first functions on `Array.prototype` and other similar structures.
Eweda's API, on the other hand is designed around composition and
partial application (or currying.)  You can create new functions
easily by not passing all the arguments to something like `map`:

    var squareAll = map(square);
    squareAll(range(1, 6)); // => [1, 4, 9, 16, 25]

In all cases, functions that take one list as a parameter, have it as
their last parameter.  And those that take one function as a parameter
have it as their first one.  The API should be internally consistent,
even if it's a bit different from other libraries.

------------------------------

One other unusual feature of the library is that, although its main
data structures are lists, the underlying implementation of its list
handling is entirely replaceable.  The exposed global, `eweda` is a
function that takes a small core implementation of six properties and
returns a new version of the library, building the rest of the list-
handling on top of those six.  By default, the lists are based on
simple arrays, but you can try with other list structures.

For instance, my co-author has created a LISP/Scheme-style list
implementation in Javascript [6].  One of our test cases, `tests/
test.bootstrap.js` runs through all the list tests using a version of
eweda based on this list core.

    var ramda = eweda({
        EMPTY: null,
        isEmpty: function(list) {return list == null;},
        prepend: cons = function(x, y) {
            return function(pick) {
                return pick(x, y);
            };
        },
        head: function(fn) {
            return fn(function(x, y) {
                return x;
            });
        },
        tail: function(fn) {
            return fn(function(x, y) {
                return y;
            });
        },
        isAtom: function(x) {
            return (x !== null) && (x !== undefined) && !x.pair;
        }
    });

We can make the functions here global by calling

    ramda.installTo(this)

in a global context, and then with these functions defined:

    var square = function(x) {return x * x;};
    var odd = function(n) {return (n % 2) == 1;};

We can now call

    map(square, filter(odd, range(1, 10)));

to get something equivalent to:

    (1 9 25 49 81)

Don't worry if you can't follow the cons-car-cdr implementation,
although it's a lot of fun to play around with.  The important idea is
that the list functions are all based on the core implementation
supplied.

------------------------------

There is a fairly large set of tests (using Mocha), but they are by no
means comprehensive, serving more as an API guide than as an
exhaustive analysis of edge cases.  They are in the folder `tests`,
and can be run in a modern browser at

    <https://rawgithub.com/CrossEye/eweda/master/test/index.html>

The only documentation beyond the test suite is a Docco-annotated
version of the source, available at

    <https://rawgithub.com/CrossEye/eweda/master/docs/eweda.html>

------------------------------

The implementation is right now more concerned with elegance than with
performance.  At some point, we'll probably refactor until most of the
functions are tail-recursive and are themselves based on a few tail-
recursive functions, which we can optimize with some trampolining
technique.  But that's for later.  Right now if we run out of stack
space when our lists reach several thousands, I'm not worried; we know
of some techniques to deal with that later after we've determined for
certain what API we want to present.

------------------------------

The functions we include are mostly standard functional library list
functions, ones like `map`, `foldl`, `foldr`, `filter`, `take`,
`skip`, some object-based ones like `prop`and `func`, plain function
manipulations like `compose`, `flip`, `memoize` and various partials,
as well as a few arithmetic and logic functions.  There are 65 - 70
functions now, with some dozen aliases. (`reduce` is the same as
`foldl`.)  The full (and possibly up-to-date) list is at:

    <https://github.com/CrossEye/eweda#functions-included>

I'd love for experienced people to look at the functions and see what
is missing, what is totally unnecessary, and what could use a better
name or at least an alias.  In the latter category, I really would
like to find a better name for `foldl1`, whose name was borrowed from
Haskell.  It's the difference between a left fold with an explicit
accumulator supplied:

    var total = foldl(add, 0, range(1, 11)) // => 55

and one where the first value of the (non-empty) list is taken as the
accumulator:

    var total2 = foldl1(add, range(1, 11)); // => 55

With the automatic partial application of functions, there is no good
way to allow for dynamic functions signatures, so I can't simply
assume that `foldl` with two parameters means something different from
`foldl` with one.  So a good name to replace `foldl1` would be very
helpful.  Similarly, of course, for `foldr1`.

One function that might be surprising in its absense is an `each` or
`forEach`.  We might eventually include one, but we're trying to work
with functional programming, which means curtailing side effects.  And
`forEach`, which doesn't return anything, has no reason except for
side effects.  We have an internal one, though, which we use in one or
two places and might be convinced to expose.  We'd like to see how far
we can go without it, though.

------------------------------

In any case, this is a very long post.  I'd love to hear any feedback
you have to offer.  I'd especially love to hear suggestions about the
API design.

_____
[1] http://underscorejs.org/
[2] http://lodash.com/
[3] https://github.com/raganwald/allong.es
[4] http://fogus.github.io/lemonad/
[5] http://osteele.com/posts/2007/07/functional-javascript
[6] https://gist.github.com/buzzdecafe/5272249

  -- Scott

[toc] | [next] | [standalone]


#19994

FromStefan Weiss <krewecherl@gmail.com>
Date2013-05-28 03:00 +0200
Message-ID<ko0vjh$7c2$1@news.albasani.net>
In reply to#19964
On 2013-05-27 02:11, Scott Sauyet wrote:
>     <https://github.com/CrossEye/eweda>
> [snip]

Very interesting. I've been following the discussion on JSMentors and
playing around with Eweda (a little bit). At this point (ie, before I
can take a good look at it) I only have two questions:

1) How do you pronounce Eweda? ("yoo-dah" as in "ewe")?

2) What was your motivation for allowing different list structures than
JS arrays? Are there any examples of other list/array-like structures
that could benefit from Eweda in a JS environment?


- stefan

[toc] | [prev] | [next] | [standalone]


#19995

FromScott Sauyet <scott.sauyet@gmail.com>
Date2013-05-27 18:51 -0700
Message-ID<d8583c15-64cc-4668-aa33-6621f2e6e4fe@q8g2000vbl.googlegroups.com>
In reply to#19994
Stefan Weiss wrote:
> Scott Sauyet wrote:
>
>>     <https://github.com/CrossEye/eweda>
>> [snip]
>
> Very interesting. I've been following the discussion on JSMentors and
> playing around with Eweda (a little bit). At this point (ie, before I
> can take a good look at it) I only have two questions:
>
> 1) How do you pronounce Eweda? ("yoo-dah" as in "ewe")?

Yes, exactly.  The name is totally silly, just a play on "lambda",
with the side benefit that when I'm feeling really good about
something I did in it, I can exclaim, "Eweda lamb!"


> 2) What was your motivation for allowing different list structures than
> JS arrays? Are there any examples of other list/array-like structures
> that could benefit from Eweda in a JS environment?

Quite possibly not.  But just before I started this, I was playing
around with this:

    <https://gist.github.com/buzzdecafe/5272249>

Which allows us to pack an awful lot of Scheme-like behavior into
these simple definitions:

    function cons(x, y) {
        return function(pick) {
            return pick(x, y);
        }
    }
    function car(fn) {
        return fn(function(x, y) { return x; });
    }
    function cdr(fn) {
        return fn(function(x, y) { return y; });
    }

Those are of course not really practical for anything except the fun
of seeing how far you can take the simple concept of lists built on
nothing more than simple functions.  But that made me wonder if there
might be some other list structure than arrays which might make
sense.  I knew that everything would be built on a few simple
functions, so making that underlying implementation pluggable was not
difficult.  I just thought it might lead to something interesting.  I
did consider whether some lazy list implementation could be built that
would work.  I haven't yet tried anything with Lazy.js, but will see
if there is any way to make it work with that one.

  -- Scott

[toc] | [prev] | [next] | [standalone]


#19997

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2013-05-27 20:54 -0700
Message-ID<b773f6d6-0165-4780-927b-edbc63449233@g3g2000yqg.googlegroups.com>
In reply to#19995
On May 27, 8:51 pm, Scott Sauyet <scott.sau...@gmail.com> wrote:
> Stefan Weiss wrote:
> > Scott Sauyet wrote:
>
> >>     <https://github.com/CrossEye/eweda>
> >> [snip]
>
> > Very interesting. I've been following the discussion on JSMentors and
> > playing around with Eweda (a little bit). At this point (ie, before I
> > can take a good look at it) I only have two questions:
>
> > 1) How do you pronounce Eweda? ("yoo-dah" as in "ewe")?
>
> Yes, exactly.  The name is totally silly, just a play on "lambda",
> with the side benefit that when I'm feeling really good about
> something I did in it, I can exclaim, "Eweda lamb!"
>
> > 2) What was your motivation for allowing different list structures than
> > JS arrays? Are there any examples of other list/array-like structures
> > that could benefit from Eweda in a JS environment?
>
> Quite possibly not.  But just before I started this, I was playing
> around with this:
>
>     <https://gist.github.com/buzzdecafe/5272249>
>
> Which allows us to pack an awful lot of Scheme-like behavior into
> these simple definitions:
>
>     function cons(x, y) {
>         return function(pick) {
>             return pick(x, y);
>         }
>     }
>     function car(fn) {
>         return fn(function(x, y) { return x; });
>     }
>     function cdr(fn) {
>         return fn(function(x, y) { return y; });
>     }
>
> Those are of course not really practical for anything except the fun
> of seeing how far you can take the simple concept of lists built on
> nothing more than simple functions.  But that made me wonder if there
> might be some other list structure than arrays which might make
> sense.  I knew that everything would be built on a few simple
> functions, so making that underlying implementation pluggable was not
> difficult.  I just thought it might lead to something interesting.  I
> did consider whether some lazy list implementation could be built that
> would work.  I haven't yet tried anything with Lazy.js, but will see
> if there is any way to make it work with that one.

Actually, you have the potential for this to work generically on
Trees, Stacks, Queues, Strings, Events, NodeLists, and probably more
container-like objects. (The Monoid concept + others as mentioned in
the JSMentors thread)

[toc] | [prev] | [next] | [standalone]


#19998

FromScott Sauyet <scott.sauyet@gmail.com>
Date2013-05-27 21:15 -0700
Message-ID<3258ffb7-f8dc-4c5c-baac-6e3678245888@w5g2000vbd.googlegroups.com>
In reply to#19997
Michael Haufe wrote:
> Scott Sauyet wrote:
>> Stefan Weiss wrote:
>>> Scott Sauyet wrote:
>
>>>>     <https://github.com/CrossEye/eweda>
>>> [ ... ]
>>> 2) What was your motivation for allowing different list structures than
>>> JS arrays? Are there any examples of other list/array-like structures
>>> that could benefit from Eweda in a JS environment?
>> Quite possibly not.  But just before I started this, I was playing
>> around with this:
>>     <https://gist.github.com/buzzdecafe/5272249>
>> [ ... ]
>> Those are of course not really practical for anything except the fun
>> of seeing how far you can take the simple concept of lists built on
>> nothing more than simple functions.  But that made me wonder if there
>> might be some other list structure than arrays which might make
>> sense.  I knew that everything would be built on a few simple
>> functions, so making that underlying implementation pluggable was not
>> difficult.  I just thought it might lead to something interesting.  I
>> did consider whether some lazy list implementation could be built that
>> would work.  I haven't yet tried anything with Lazy.js, but will see
>> if there is any way to make it work with that one.
>
> Actually, you have the potential for this to work generically on
> Trees, Stacks, Queues, Strings, Events, NodeLists, and probably more
> container-like objects. (The Monoid concept + others as mentioned in
> the JSMentors thread)

Yes, I'm definitely going to have to think it through.  That might
make for a very interesting library.  But it is a significant
departure from where we've been heading so far.

  -- Scott

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web