Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.javascript > #24448 > unrolled thread
| Started by | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| First post | 2014-05-27 20:13 -0700 |
| Last post | 2016-03-07 10:50 +0100 |
| Articles | 20 on this page of 34 — 7 participants |
Back to article view | Back to comp.lang.javascript
ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-27 20:13 -0700
Re: ANN: Ramda, a new functional programming library John C <rescattered@gmail.com> - 2014-05-27 21:00 -0700
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-28 04:37 -0700
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-28 04:36 -0700
Re: ANN: Ramda, a new functional programming library "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2014-05-28 08:49 -0700
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-28 15:59 -0700
Re: ANN: Ramda, a new functional programming library "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2014-05-28 16:15 -0700
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-28 17:05 -0700
Re: ANN: Ramda, a new functional programming library Christoph Michael Becker <cmbecker69@arcor.de> - 2014-05-30 14:53 +0200
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-30 11:14 -0700
Re: ANN: Ramda, a new functional programming library Dr J R Stockton <reply1400@merlyn.demon.co.uk.invalid> - 2014-05-29 19:40 +0100
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-29 17:55 -0700
Re: ANN: Ramda, a new functional programming library Christoph Michael Becker <cmbecker69@arcor.de> - 2014-05-30 14:05 +0200
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-30 11:10 -0700
Re: ANN: Ramda, a new functional programming library John C <rescattered@gmail.com> - 2014-05-30 06:25 -0700
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-30 11:23 -0700
Re: ANN: Ramda, a new functional programming library John C <rescattered@gmail.com> - 2014-05-30 12:44 -0700
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-30 13:39 -0700
Re: ANN: Ramda, a new functional programming library John C <rescattered@gmail.com> - 2014-05-30 19:17 -0700
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-05-31 09:52 -0700
Re: ANN: Ramda, a new functional programming library Christoph Michael Becker <cmbecker69@arcor.de> - 2014-05-31 22:24 +0200
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-06-01 06:55 -0700
Re: ANN: Ramda, a new functional programming library Christoph Michael Becker <cmbecker69@arcor.de> - 2014-05-31 21:00 +0200
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-06-01 06:54 -0700
Re: ANN: Ramda, a new functional programming library Dr J R Stockton <reply1400@merlyn.demon.co.uk.invalid> - 2014-06-01 19:05 +0100
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-06-01 19:28 -0700
Re: ANN: Ramda, a new functional programming library Dr J R Stockton <reply1400@merlyn.demon.co.uk.invalid> - 2014-06-03 22:01 +0100
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-06-03 19:15 -0700
Re: ANN: Ramda, a new functional programming library Dr J R Stockton <reply1400@merlyn.demon.co.uk.invalid> - 2014-06-05 23:41 +0100
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2014-06-06 11:36 -0700
Re: ANN: Ramda, a new functional programming library Dr J R Stockton <reply1400@merlyn.demon.co.uk.invalid> - 2014-06-07 23:13 +0100
Re: ANN: Ramda, a new functional programming library billyroberts111@gmail.com - 2016-03-06 10:22 -0800
Re: ANN: Ramda, a new functional programming library Scott Sauyet <scott.sauyet@gmail.com> - 2016-03-06 17:52 -0800
Re: ANN: Ramda, a new functional programming library "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2016-03-07 10:50 +0100
Page 1 of 2 [1] 2 Next page →
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-27 20:13 -0700 |
| Subject | ANN: Ramda, a new functional programming library |
| Message-ID | <da2909bd-58cc-4183-8b3c-167039985491@googlegroups.com> |
I've been away from this group a while, and probably will not be
around for long this time, as I'm pretty buried in several projects
that haven't left me much spare time. But I wanted to announce my
current project. I'll check in regularly for a while to read responses.
I'm looking for feedback on a new functional programming library for
Javascript that I've been developing with a friend. This may seem
very familiar to those who saw a similar request a year ago. That was
for a different library, which turned out to be more of academic
interest. This one was originally based on that project, eweda, but
with a more practical bent.
The library is called "ramda", which is just a silly pun on "lambda".
My co-author has just published a brief introduction at
<http://buzzdecafe.github.io/code/2014/05/16/introducing-ramda/>
The project is on Github, at
<https://github.com/CrossEye/ramda>
and the library is (temporarily, at least) in a single source file:
<https://github.com/CrossEye/ramda/blob/master/ramda.js>
You can install it for a Node.js project with
npm install ramda
------------------------------
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
object, `ramda`:
var square = function(x) {return x * x;};
var nbrs = ramda.range(1, 5); // => [1, 2, 3, 4]
var squares = ramda.map(square, nbrs); // => [1, 4, 9, 16]
But they can be attached to any object, including the global object
via `ramda.installTo()`. This will pollute the global namespace with
a number of functions, but is one possible means of using 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.
Ramda'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.
------------------------------
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://rawgit.com/CrossEye/ramda/master/test/index.html>
The only documentation beyond the test suite is a Docco-annotated
version of the source, available at
<https://rawgit.com/CrossEye/ramda/master/docs/ramda.html>
------------------------------
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 over 100
functions now, with some dozen aliases. (`reduce` is the same as
`foldl`.)
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`.
------------------------------
We also have a few functions that we think are unique to Ramda. Two
examples are:
- `when` is similar to functions in other libraries that accept an
object specification and return a predicate that can be used to
test additional objects. Ramda's `when` takes more than just
individual values for specification, though; it can also take
functions:
isTriangular = where({
sides: 3,
a: function(a, t) {return a < t.b + t.c;},
b: function(b, t) {return b < t.a + t.c;},
c: function(c, t) {return c < t.a + t.b;}
});
isTriangular({sides: 5}); //=> false
isTriangular({sides: 3, a: 2, b: 1, c: 7}); //=> false
isTriangular({sides: 3, a: 3, b: 4, c: 5}); //=> true
- `useWith`. We still haven't decided which of the two APIs
for this function we prefer, and for the moment are including
both. This function combines a number of configuration functions
with a single gathering function and returns a new function. When
the resulting function is called, the arguments are supplied,
respectively, to each of the configuration functions, and the
results of these functions are all passed to the gathering
function. This allows us to define Codd's `project` (similar to
SQL `select`) for lists of objects with quite simple code:
project = useWith(map, pickAll, identity); // OR (other API)
project = use(map).over(pickAll, identity);
This would get used like this:
var kids = [
{name: 'Abby', age: 7, hair: 'blond'},
{name: 'Fred', age: 12, hair: 'brown'},
{name: 'Rusty', age: 10, hair: 'brown'},
{name: 'Alois', age: 15, disposition: 'surly'}
];
filter(propEq("hair", "brown"), kids);
//=> Fred and Rusty
------------------------------
The library has a facility for creating lazy infinite lists; we're in
the process of pulling that out of the core and making it a separate
extension. In fact we want to have a bundle-building mechanism to
allow you to create your own package, the way Modernizr and David
Mark's MyLibrary (is that still around?) do.
But that infrastructure work has never really made it to the top of
our list of priorities. We've just picked up a volunteer to help with
documentation, so soon the library might be better documented.
But we're still mostly focused on code. And perhaps the biggest thing
left is to implement some of the standard algebraic types, such as
Functor, Applicative, Monoid, and Monad, as well as some standard
objects implementing those, such as Maybe, Either, and IO. This is
well underway, and will probably be ready within weeks.
------------------------------
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.
Thanks,
-- Scott,
_____
[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
[toc] | [next] | [standalone]
| From | John C <rescattered@gmail.com> |
|---|---|
| Date | 2014-05-27 21:00 -0700 |
| Message-ID | <aff02561-f06e-412c-aa0a-06cf9088b930@googlegroups.com> |
| In reply to | #24448 |
On Tuesday, May 27, 2014 11:13:11 PM UTC-4, Scott Sauyet wrote:
> I've been away from this group a while, and probably will not be
>
> around for long this time, as I'm pretty buried in several projects
>
> that haven't left me much spare time. But I wanted to announce my
>
> current project. I'll check in regularly for a while to read responses.
>
>
>
> I'm looking for feedback on a new functional programming library for
>
> Javascript that I've been developing with a friend. This may seem
>
> very familiar to those who saw a similar request a year ago. That was
>
> for a different library, which turned out to be more of academic
>
> interest. This one was originally based on that project, eweda, but
>
> with a more practical bent.
>
>
>
> The library is called "ramda", which is just a silly pun on "lambda".
>
>
>
> My co-author has just published a brief introduction at
>
>
>
> <http://buzzdecafe.github.io/code/2014/05/16/introducing-ramda/>
>
>
>
> The project is on Github, at
>
>
>
> <https://github.com/CrossEye/ramda>
>
>
>
> and the library is (temporarily, at least) in a single source file:
>
>
>
> <https://github.com/CrossEye/ramda/blob/master/ramda.js>
>
>
>
> You can install it for a Node.js project with
>
>
>
> npm install ramda
>
>
>
> ------------------------------
>
>
>
> 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
>
> object, `ramda`:
>
>
>
> var square = function(x) {return x * x;};
>
> var nbrs = ramda.range(1, 5); // => [1, 2, 3, 4]
>
> var squares = ramda.map(square, nbrs); // => [1, 4, 9, 16]
>
>
>
> But they can be attached to any object, including the global object
>
> via `ramda.installTo()`. This will pollute the global namespace with
>
> a number of functions, but is one possible means of using 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.
>
> Ramda'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.
>
>
>
> ------------------------------
>
>
>
> 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://rawgit.com/CrossEye/ramda/master/test/index.html>
>
>
>
> The only documentation beyond the test suite is a Docco-annotated
>
> version of the source, available at
>
>
>
> <https://rawgit.com/CrossEye/ramda/master/docs/ramda.html>
>
>
>
> ------------------------------
>
>
>
> 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 over 100
>
> functions now, with some dozen aliases. (`reduce` is the same as
>
> `foldl`.)
>
>
>
> 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`.
>
>
>
> ------------------------------
>
>
>
> We also have a few functions that we think are unique to Ramda. Two
>
> examples are:
>
>
>
> - `when` is similar to functions in other libraries that accept an
>
> object specification and return a predicate that can be used to
>
> test additional objects. Ramda's `when` takes more than just
>
> individual values for specification, though; it can also take
>
> functions:
>
>
>
> isTriangular = where({
>
> sides: 3,
>
> a: function(a, t) {return a < t.b + t.c;},
>
> b: function(b, t) {return b < t.a + t.c;},
>
> c: function(c, t) {return c < t.a + t.b;}
>
> });
>
>
>
> isTriangular({sides: 5}); //=> false
>
> isTriangular({sides: 3, a: 2, b: 1, c: 7}); //=> false
>
> isTriangular({sides: 3, a: 3, b: 4, c: 5}); //=> true
>
>
>
> - `useWith`. We still haven't decided which of the two APIs
>
> for this function we prefer, and for the moment are including
>
> both. This function combines a number of configuration functions
>
> with a single gathering function and returns a new function. When
>
> the resulting function is called, the arguments are supplied,
>
> respectively, to each of the configuration functions, and the
>
> results of these functions are all passed to the gathering
>
> function. This allows us to define Codd's `project` (similar to
>
> SQL `select`) for lists of objects with quite simple code:
>
>
>
> project = useWith(map, pickAll, identity); // OR (other API)
>
> project = use(map).over(pickAll, identity);
>
>
>
> This would get used like this:
>
>
>
> var kids = [
>
> {name: 'Abby', age: 7, hair: 'blond'},
>
> {name: 'Fred', age: 12, hair: 'brown'},
>
> {name: 'Rusty', age: 10, hair: 'brown'},
>
> {name: 'Alois', age: 15, disposition: 'surly'}
>
> ];
>
> filter(propEq("hair", "brown"), kids);
>
> //=> Fred and Rusty
>
>
>
> ------------------------------
>
>
>
> The library has a facility for creating lazy infinite lists; we're in
>
> the process of pulling that out of the core and making it a separate
>
> extension. In fact we want to have a bundle-building mechanism to
>
> allow you to create your own package, the way Modernizr and David
>
> Mark's MyLibrary (is that still around?) do.
>
>
>
> But that infrastructure work has never really made it to the top of
>
> our list of priorities. We've just picked up a volunteer to help with
>
> documentation, so soon the library might be better documented.
>
>
>
> But we're still mostly focused on code. And perhaps the biggest thing
>
> left is to implement some of the standard algebraic types, such as
>
> Functor, Applicative, Monoid, and Monad, as well as some standard
>
> objects implementing those, such as Maybe, Either, and IO. This is
>
> well underway, and will probably be ready within weeks.
>
>
>
> ------------------------------
>
>
>
> 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.
>
>
>
> Thanks,
>
>
>
> -- Scott,
>
>
>
> _____
>
> [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
Nice. The code on Github looks very well organized -- I like how well-commented it is. I'm not sure what the point in trying to emulate Haskell too much would be (things such as Maybe or IO) since I thought that the point of those sorts of monads was to get around Haskell's rigid type system and lack of side effects. In the context of javascript wouldn't they be trying to solve a problem that javascript doesn't have? I would think that a functional language like ML which isn't afraid of side-effects would be a closer fit to javascript.
In any event -- I have a hobby project that I want to work on this summer to port some image-producing Haskell code I wrote in the past to javascript so I can display the resulting images on an html canvas. Your library looks like it might be a promising way to go.
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-28 04:37 -0700 |
| Message-ID | <1868ca82-5747-4fe2-a98c-a8c5361be6d9@googlegroups.com> |
| In reply to | #24449 |
John C wrote:
> Scott Sauyet wrote:
>> I'm looking for feedback on a new functional programming library for
>> Javascript [ ... ]
>> <https://github.com/CrossEye/ramda> [ ... ]
> Nice. The code on Github looks very well organized -- I like how
> well-commented it is.
Thank you. If nothing else, that helps us maintain a minimal amount of
documentation in the form of annotated source code:
<https://rawgit.com/CrossEye/ramda/master/docs/ramda.html>
> I'm not sure what the point in trying to emulate Haskell too much
> would be (things such as Maybe or IO) since I thought that the point
> of those sorts of monads was to get around Haskell's rigid type system
> and lack of side effects.
I don't think Haskellers would be suggesting attempts to get around their
precious type system! :-)
Right now where Ramda really is useful is in dealing with data objects;
it's very powerful at mapping, filtering, reducing, and many other
straightforward FP techniques for manipulating data. But we'd like to
extend it into other parts of the front-end stack, places less orderly,
such as dealing with the DOM, with HTTP and other asynchronous processes.
In order to deal with these, we'd like to have something like `Maybe`
Functor which isolates the null-checking to a single place. We probably
wouldn't need Haskell's `Just` and `Nothing` subclasses, as Javascript's
looser type system will let us handle things just fine with a single
`Maybe` whose value may or may not be null. But when we fmap over a
`Maybe` we then don't have any further worries about whether the value
is null. Only at the very end, when we're unpacking our data again do we
have to check it.
Similarly, we'd like to build our systems by composing functions, and
then triggering them based on some events. But our functions will not be
entirely pure; we will want to update the DOM, make a server request, or
create some other side-effect along the way. But we still want our pure
functions to be as straightforward as possible. Something like the `IO`
Monad could help us to segregate the pure from the impure.
> In the context of javascript wouldn't they be trying to solve a
> problem that javascript doesn't have? I would think that a functional
> language like ML which isn't afraid of side-effects would be a closer
> fit to javascript.
We're not doing this in isolation. A lot of projects are trying to
implement a common specification for these algebraic types:
<https://github.com/fantasyland/fantasy-land>
I have the feeling that these folks are Clojure and Scala folks more
than Haskell. I've never really learned ML, although I find I can read
it reasonably well.
> In any event -- I have a hobby project that I want to work on this
> summer to port some image-producing Haskell code I wrote in the past
> to javascript so I can display the resulting images on an html canvas.
> Your library looks like it might be a promising way to go.
Best of luck with that. Feel free to email if you're looking for help
with the library.
-- Scott
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-28 04:36 -0700 |
| Message-ID | <2f5fd1b2-271b-4460-87e0-b1ad81ddd379@googlegroups.com> |
| In reply to | #24448 |
Scott Sauyet wrote:
> I'm looking for feedback on a new functional programming library for
> Javascript [ ... ]
> <https://github.com/CrossEye/ramda> [ ... ]
I guess I was getting sleepy when I finally posted this, as I copied the
wrong example to illustrate this section:
> - `useWith`. We still haven't decided which of the two APIs
> for this function we prefer, and for the moment are including
> both. This function combines a number of configuration functions
> with a single gathering function and returns a new function. When
> the resulting function is called, the arguments are supplied,
> respectively, to each of the configuration functions, and the
> results of these functions are all passed to the gathering
> function. This allows us to define Codd's `project` (similar to
> SQL `select`) for lists of objects with quite simple code:
>
> project = useWith(map, pickAll, identity); // OR (other API)
> project = use(map).over(pickAll, identity);
`project` would actually get used like this:
var kids = [
{name: 'Abby', age: 7, hair: 'blond', grade: 2},
{name: 'Fred', age: 12, hair: 'brown', grade: 7}
];
project(['name', 'grade'], kids);
//=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}]
Of course the point of that section was to demonstrate `useWith`/`use.over`,
but I still prefer to have the examples meaningful.
The point is that `useWith` returned a function (assigned to `project`) that
takes a list of property names, passes it to `pickAll`, a list of objects,
passes it to `identity`, and then passes the results of those functions to
`map`. (This works because `pickAll` is curried, but that's true of pretty
well all functions of more than one parameter in the library.)
Sorry if anyone was confused by the earlier example.
-- Scott
[toc] | [prev] | [next] | [standalone]
| From | "Michael Haufe (TNO)" <tno@thenewobjective.com> |
|---|---|
| Date | 2014-05-28 08:49 -0700 |
| Message-ID | <737583eb-f24f-4f9a-a221-4c1677f59932@googlegroups.com> |
| In reply to | #24448 |
On Tuesday, May 27, 2014 10:13:11 PM UTC-5, Scott Sauyet wrote: > I've been away from this group a while, and probably will not be > around for long this time, as I'm pretty buried in several projects > that haven't left me much spare time. But I wanted to announce my > current project. I'll check in regularly for a while to read responses. > > [...] Would you mind giving me an update on things since our last conversations? https://groups.google.com/d/topic/jsmentors/0Cj7AEH5Oic/discussion https://groups.google.com/d/topic/jsmentors/wH6X8SDPnbw/discussion
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-28 15:59 -0700 |
| Message-ID | <ead75684-b2f7-4ea2-b758-02fac986f26b@googlegroups.com> |
| In reply to | #24457 |
Michael Haufe (TNO) wrote:
> Scott Sauyet wrote:
>> I've been away from this group a while, and probably will not be
>> around for long this time, as I'm pretty buried in several projects
>> that haven't left me much spare time. But I wanted to announce my
>> current project. I'll check in regularly for a while to read responses.
>> [...]
>
> Would you mind giving me an update on things since our last conversations?
>
> https://groups.google.com/d/topic/jsmentors/0Cj7AEH5Oic/discussion
> https://groups.google.com/d/topic/jsmentors/wH6X8SDPnbw/discussion
Regarding ideas about functional composition discussed in one of those
threads, this library does not attempt to address anything but the
standard notion of `compose` used in many FP contexts, although it
also adds `pipe`, which simply does the same thing with the arguments
in the reverse order. For example,
var factorial = compose(product, range(1), add(1));
is equivalent to
var factorial = pipe(add(1), range(1), product);
(As discussed previously, our `range` is inclusive on the left,
exclusive on the right, which necessitates the `add(1)` call.)
I find `pipe` more intuitive than `compose`, but obviously there's not
much difference. We do have one other compose-like function included,
the `useWith` mentioned in the OP. I have given a brief talk on
functional composition in several forums; the slides are here:
<http://scott.sauyet.com/Javascript/Talk/Compose/>
------------------------------
The other thread was a long-ranging discussion about the predecessor
to ramda, a library called eweda. Although the original goal of eweda
was to be a practical library, we quickly became seduced by
implementation elegance and did not build a very performant or, in the
end, a very useful library. Ramda takes a very different approach.
The library tries to be efficient and useful. It keeps the same API
as eweda, focusing on simple, composable, pre-curried functions that
do much of the standard list-, object-, string-, number-, and
function-manipulation that you might expect.
There are probably few surprises in Ramda for someone who has
programmed in a functional language. The ideas was to take some of
the things that are most sorely missed when switching to Javascript
and make them available. Next up will be the algebraic data types.
This library does not have the replaceable core list implementation
featured in eweda. Its lists are arrays. It does, though have the
ability to deal with infinite lazy lists created by generators. (We
are in the process of trying to build a bundling system; these lazy
lists may well end up being an optional feature not included in the
core bundle, but the code is available, and still included by default
at the moment.)
The biggest change from those discussions is one of maturity. The
library has grown, become better tested, more hardened, and I'm
hoping, more all-around useful. It no longer feels like an API
experiment; it feels like a working product.
HTH,
-- Scott
[toc] | [prev] | [next] | [standalone]
| From | "Michael Haufe (TNO)" <tno@thenewobjective.com> |
|---|---|
| Date | 2014-05-28 16:15 -0700 |
| Message-ID | <438d5065-ea6f-437f-a9da-f3712efda2d3@googlegroups.com> |
| In reply to | #24459 |
On Wednesday, May 28, 2014 5:59:12 PM UTC-5, Scott Sauyet wrote: > [...] > > There are probably few surprises in Ramda for someone who has > programmed in a functional language. The ideas was to take some of > the things that are most sorely missed when switching to Javascript > and make them available. Next up will be the algebraic data types. > > [...] I'll try to make time for a better follow-up in a couple days. For now I'd like to forward you the follow reference which you might find useful for ADTs: <http://w3future.com/weblog/stories/2008/06/16/adtinjs.xml> 1. What version of ECMAScript are you assuming? 2. How do/will you manage a collection of related functions? Since you are avoiding OO, and don't have the luxury of Type Classes, what will you do? This issue will be important for when you get around to things such as Monoids. ADTs could be an escape hatch here.
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-28 17:05 -0700 |
| Message-ID | <2d59b8d0-7ca1-4494-a88d-3c171b73abe6@googlegroups.com> |
| In reply to | #24460 |
Michael Haufe (TNO) wrote:
> Scott Sauyet wrote:
>> [...]
>> There are probably few surprises in Ramda for someone who has
>> programmed in a functional language. The ideas was to take some of
>> the things that are most sorely missed when switching to Javascript
>> and make them available. Next up will be the algebraic data types.
>> [...]
>
> I'll try to make time for a better follow-up in a couple days. For
> now I'd like to forward you the follow reference which you might find
> useful for ADTs:
>
> <http://w3future.com/weblog/stories/2008/06/16/adtinjs.xml>
I've glanced through it and it looks interesting. I will try to give
it more attention tonight. But I'm not sure it's really relevant to
what we're considering. We really weren't considering a general
algebraic type solution, but rather a collection of common ones such
as Functor, Applicative, Monoid, and Monad. We'd consider
implementing the FantasyLand specification:
<https://github.com/fantasyland/fantasy-land>
> 1. What version of ECMAScript are you assuming?
We haven't made any particular assumptions. But I'm guessing that the
code will run in ES3. We want it to work in any modern browser or
server-side implementation, but don't expect that to be an issue.
> 2. How do/will you manage a collection of related functions? Since
> you are avoiding OO, and don't have the luxury of Type Classes, what
> will you do? This issue will be important for when you get around to
> things such as Monoids. ADTs could be an escape hatch here.
We are not avoiding OO. So I'm not overly worried. We are adding
functional techniques, but we are trying to be practical about the
fact that this is Javascript.
-- Scott
[toc] | [prev] | [next] | [standalone]
| From | Christoph Michael Becker <cmbecker69@arcor.de> |
|---|---|
| Date | 2014-05-30 14:53 +0200 |
| Message-ID | <53887f3e$0$6669$9b4e6d93@newsspool3.arcor-online.net> |
| In reply to | #24462 |
Scott Sauyet wrote: > Michael Haufe (TNO) wrote: > >> 1. What version of ECMAScript are you assuming? > > We haven't made any particular assumptions. But I'm guessing that the > code will run in ES3. We want it to work in any modern browser or > server-side implementation, but don't expect that to be an issue. While having a look at the documentation, I noticed that ramda.contains and ramda.indexOf are using Array.prototype.indexOf, which was introduced in ES 5.1 only. IMHO not a problem, but maybe good to be aware of. -- Christoph M. Becker
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-30 11:14 -0700 |
| Message-ID | <967fa4e5-cb69-40a0-b709-68eecd8701b4@googlegroups.com> |
| In reply to | #24476 |
Christoph Michael Becker wrote: > Scott Sauyet wrote: >> Michael Haufe (TNO) wrote: >>> 1. What version of ECMAScript are you assuming? >> We haven't made any particular assumptions. But I'm guessing that the >> code will run in ES3. We want it to work in any modern browser or >> server-side implementation, but don't expect that to be an issue. > > While having a look at the documentation, I noticed that ramda.contains > and ramda.indexOf are using Array.prototype.indexOf, which was > introduced in ES 5.1 only. IMHO not a problem, but maybe good to be > aware of. You're absolutely right. I'd forgotten that. We probably won't be working hard (read: at all) to get this to work with pre-ES5 browsers, so we might well end up insisting on that as a minimal requirement, expecting that those who need to use it in an older environment would need to have at least `Array.prototype.indexOf` shimmed. But we haven't really made those decisions yet. -- Scott
[toc] | [prev] | [next] | [standalone]
| From | Dr J R Stockton <reply1400@merlyn.demon.co.uk.invalid> |
|---|---|
| Date | 2014-05-29 19:40 +0100 |
| Message-ID | <micPD5QG83hTFwI8@invalid.uk.co.demon.merlyn.invalid> |
| In reply to | #24448 |
In comp.lang.javascript message <da2909bd-58cc-4183-8b3c-167039985491@go oglegroups.com>, Tue, 27 May 2014 20:13:11, Scott Sauyet <scott.sauyet@gmail.com> posted: >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`. Words with meanings like "fold" include "crease", "pleat", "plait", "enfold", "infold", "embrace", and anything that Google Translate offers as equivalent for any of those. For example, "plygu", "cris", "gofleidio", "falt", "taittaa", "plegar", "ninka", "huaire", "darbiet", "korukoru", "phinda", etc. -- (c) John Stockton, nr London, UK. Mail via homepage. Turnpike v6.05 MIME. Web <http://www.merlyn.demon.co.uk/> - FAQqish topics, acronyms and links; Astro stuff via astron-1.htm, gravity0.htm ; quotings.htm, pascal.htm, etc.
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-29 17:55 -0700 |
| Message-ID | <181c0b33-8dc3-459e-bb3a-f9549ded4276@googlegroups.com> |
| In reply to | #24466 |
Dr J R Stockton wrote: > Scott Sauyet posted: >> 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`. > > Words with meanings like "fold" include "crease", "pleat", "plait", > "enfold", "infold", "embrace", and anything that Google Translate offers > as equivalent for any of those. For example, "plygu", "cris", > "gofleidio", "falt", "taittaa", "plegar", "ninka", "huaire", "darbiet", > "korukoru", "phinda", etc. Thank you. I'm not even going to try to guess at the languages. :-) If you are not familiar with foldl/foldr or their aliases of reduce/reduceRight, these are common functional construct that combine lists of elements into a single value, accepting an initial value and a function that combines the current value and the next list element into a new value. The ES5 specification defines `Array.prototype.reduce` [1] and `Array.prototype.reduceRight` [2]. While these work well in modern implementations, they are not the functional constructs that the Ramda library is developing. The most obvious difference between foldl and foldr is that foldl processes the from the first (leftmost) element of the list to the last, whereas foldr processes in ther reverse direction. That is not the only difference, but the other subtleties aren't important here. The difference between `foldl` and `foldl1` is simply that the former is supplied the initial value; the latter extracts it as the first element of the list (and therefore requires a non-empty list.) This also means that the type of the accumulators for `foldl1`, and therefore also of the output should be the same as the types of the elements of the list. But this, in my experience, is the norm even in `foldl`. Obviously, the same things apply to `foldr1`. Note that the gap between the definitions of 'fold' and 'reduce', which here are used as aliases, make it less likely that a synonym for 'fold' would be a reasonable name to replace 'foldl1' or 'foldr1'. Probably the most likely notion of folding that applies is something like an accordion fold. And maybe something along those lines would do. What I was really hoping is that someone with experience with this in another functional language would be able to pipe up and say, "Oh yes, that's often called 'XYZ'." But I really don't think it's likely. Thanks for the input! -- Scott [1] http://ecma-international.org/ecma-262/5.1/#sec-15.4.4.21 [2] http://ecma-international.org/ecma-262/5.1/#sec-15.4.4.22
[toc] | [prev] | [next] | [standalone]
| From | Christoph Michael Becker <cmbecker69@arcor.de> |
|---|---|
| Date | 2014-05-30 14:05 +0200 |
| Message-ID | <53887415$0$6655$9b4e6d93@newsspool3.arcor-online.net> |
| In reply to | #24469 |
Scott Sauyet wrote: > Note that the gap between the definitions of 'fold' and 'reduce', > which here are used as aliases, make it less likely that a synonym > for 'fold' would be a reasonable name to replace 'foldl1' or 'foldr1'. > Probably the most likely notion of folding that applies is something > like an accordion fold. And maybe something along those lines would > do. What I was really hoping is that someone with experience with > this in another functional language would be able to pipe up and say, > "Oh yes, that's often called 'XYZ'." But I really don't think it's > likely. There is an overview on Wikipedia[1], which you might not be aware of. As I have (yet) very little experience with functional programming (languages), I can't comment on this, though. [1] <http://en.wikipedia.org/wiki/Fold_(higher-order_function)#Folds_in_various_languages> -- Christoph M. Becker
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-30 11:10 -0700 |
| Message-ID | <132b64cd-f936-431c-8099-08a32e362dd2@googlegroups.com> |
| In reply to | #24473 |
Christoph Michael Becker wrote: > Scott Sauyet wrote: > >> Note that the gap between the definitions of 'fold' and 'reduce', >> which here are used as aliases, make it less likely that a synonym >> for 'fold' would be a reasonable name to replace 'foldl1' or 'foldr1'. >> Probably the most likely notion of folding that applies is something >> like an accordion fold. And maybe something along those lines would >> do. What I was really hoping is that someone with experience with >> this in another functional language would be able to pipe up and say, >> "Oh yes, that's often called 'XYZ'." But I really don't think it's >> likely. > > There is an overview on Wikipedia[1], which you might not be aware of. > As I have (yet) very little experience with functional programming > (languages), I can't comment on this, though. > > [1] <http://en.wikipedia.org/wiki/Fold_(higher-order_function)#Folds_in_various_languages> I hadn't seen that, and it looks as though it might be quite helpful. Thank you. -- Scott
[toc] | [prev] | [next] | [standalone]
| From | John C <rescattered@gmail.com> |
|---|---|
| Date | 2014-05-30 06:25 -0700 |
| Message-ID | <02dfeef2-b8fa-4cc3-8c6f-d375a43278ca@googlegroups.com> |
| In reply to | #24448 |
On Tuesday, May 27, 2014 11:13:11 PM UTC-4, Scott Sauyet wrote:
> I've been away from this group a while, and probably will not be
>
> around for long this time, as I'm pretty buried in several projects
>
> that haven't left me much spare time. But I wanted to announce my
>
> current project. I'll check in regularly for a while to read responses.
>
>
>
> I'm looking for feedback on a new functional programming library for
>
> Javascript that I've been developing with a friend. This may seem
>
> very familiar to those who saw a similar request a year ago. That was
>
> for a different library, which turned out to be more of academic
>
> interest. This one was originally based on that project, eweda, but
>
> with a more practical bent.
>
>
>
> The library is called "ramda", which is just a silly pun on "lambda".
>
>
>
> My co-author has just published a brief introduction at
>
>
>
> <http://buzzdecafe.github.io/code/2014/05/16/introducing-ramda/>
>
>
>
> The project is on Github, at
>
>
>
> <https://github.com/CrossEye/ramda>
>
>
>
> and the library is (temporarily, at least) in a single source file:
>
>
>
> <https://github.com/CrossEye/ramda/blob/master/ramda.js>
>
>
>
> You can install it for a Node.js project with
>
>
>
> npm install ramda
>
>
>
> ------------------------------
>
>
>
> 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
>
> object, `ramda`:
>
>
>
> var square = function(x) {return x * x;};
>
> var nbrs = ramda.range(1, 5); // => [1, 2, 3, 4]
>
> var squares = ramda.map(square, nbrs); // => [1, 4, 9, 16]
>
>
>
> But they can be attached to any object, including the global object
>
> via `ramda.installTo()`. This will pollute the global namespace with
>
> a number of functions, but is one possible means of using 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.
>
> Ramda'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.
>
>
>
> ------------------------------
>
>
>
> 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://rawgit.com/CrossEye/ramda/master/test/index.html>
>
>
>
> The only documentation beyond the test suite is a Docco-annotated
>
> version of the source, available at
>
>
>
> <https://rawgit.com/CrossEye/ramda/master/docs/ramda.html>
>
>
>
> ------------------------------
>
>
>
> 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 over 100
>
> functions now, with some dozen aliases. (`reduce` is the same as
>
> `foldl`.)
>
>
>
> 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`.
>
>
>
> ------------------------------
>
>
>
> We also have a few functions that we think are unique to Ramda. Two
>
> examples are:
>
>
>
> - `when` is similar to functions in other libraries that accept an
>
> object specification and return a predicate that can be used to
>
> test additional objects. Ramda's `when` takes more than just
>
> individual values for specification, though; it can also take
>
> functions:
>
>
>
> isTriangular = where({
>
> sides: 3,
>
> a: function(a, t) {return a < t.b + t.c;},
>
> b: function(b, t) {return b < t.a + t.c;},
>
> c: function(c, t) {return c < t.a + t.b;}
>
> });
>
>
>
> isTriangular({sides: 5}); //=> false
>
> isTriangular({sides: 3, a: 2, b: 1, c: 7}); //=> false
>
> isTriangular({sides: 3, a: 3, b: 4, c: 5}); //=> true
>
>
>
> - `useWith`. We still haven't decided which of the two APIs
>
> for this function we prefer, and for the moment are including
>
> both. This function combines a number of configuration functions
>
> with a single gathering function and returns a new function. When
>
> the resulting function is called, the arguments are supplied,
>
> respectively, to each of the configuration functions, and the
>
> results of these functions are all passed to the gathering
>
> function. This allows us to define Codd's `project` (similar to
>
> SQL `select`) for lists of objects with quite simple code:
>
>
>
> project = useWith(map, pickAll, identity); // OR (other API)
>
> project = use(map).over(pickAll, identity);
>
>
>
> This would get used like this:
>
>
>
> var kids = [
>
> {name: 'Abby', age: 7, hair: 'blond'},
>
> {name: 'Fred', age: 12, hair: 'brown'},
>
> {name: 'Rusty', age: 10, hair: 'brown'},
>
> {name: 'Alois', age: 15, disposition: 'surly'}
>
> ];
>
> filter(propEq("hair", "brown"), kids);
>
> //=> Fred and Rusty
>
>
>
> ------------------------------
>
>
>
> The library has a facility for creating lazy infinite lists; we're in
>
> the process of pulling that out of the core and making it a separate
>
> extension. In fact we want to have a bundle-building mechanism to
>
> allow you to create your own package, the way Modernizr and David
>
> Mark's MyLibrary (is that still around?) do.
>
>
>
> But that infrastructure work has never really made it to the top of
>
> our list of priorities. We've just picked up a volunteer to help with
>
> documentation, so soon the library might be better documented.
>
>
>
> But we're still mostly focused on code. And perhaps the biggest thing
>
> left is to implement some of the standard algebraic types, such as
>
> Functor, Applicative, Monoid, and Monad, as well as some standard
>
> objects implementing those, such as Maybe, Either, and IO. This is
>
> well underway, and will probably be ready within weeks.
>
>
>
> ------------------------------
>
>
>
> 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.
>
>
>
> Thanks,
>
>
>
> -- Scott,
>
>
>
> _____
>
> [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
As far as your name for foldl1 goes -- how about selfFoldl since in that case
it folds in on itself (as opposed to folding on an externally given item)?
Another idea is something like "rollUp"
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-30 11:23 -0700 |
| Message-ID | <2c61b020-8e0c-4a3b-a021-f7058aed52dc@googlegroups.com> |
| In reply to | #24478 |
John C wrote: > Scott Sauyet wrote: >> [ ... ] >> <https://github.com/CrossEye/ramda> >> [ ... ] >> 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`. [ ... ] > As far as your name for foldl1 goes -- how about selfFoldl since in > that case it folds in on itself (as opposed to folding on an externally > given item)? Another idea is something like "rollUp" Those both sound quite good. Thank you for the suggestions. The funny thing is that I'd forgotten we'd taken these out of the library in response to a disagreement over how to handle the case where the user supplied an empty list. At some point we'll probably put them back, but they're not there now. When they do come back, maybe we'll use `selfFoldl`. Thanks, -- Scott
[toc] | [prev] | [next] | [standalone]
| From | John C <rescattered@gmail.com> |
|---|---|
| Date | 2014-05-30 12:44 -0700 |
| Message-ID | <72aa659a-997d-4d1a-97bb-87ffef38978c@googlegroups.com> |
| In reply to | #24489 |
On Friday, May 30, 2014 2:23:48 PM UTC-4, Scott Sauyet wrote: > John C wrote: > > > Scott Sauyet wrote: > > >> [ ... ] > > >> <https://github.com/CrossEye/ramda> > > >> [ ... ] > > >> 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`. [ ... ] > > > > > As far as your name for foldl1 goes -- how about selfFoldl since in > > > that case it folds in on itself (as opposed to folding on an externally > > > given item)? Another idea is something like "rollUp" > > > > Those both sound quite good. Thank you for the suggestions. > > > > The funny thing is that I'd forgotten we'd taken these out of the library in response to a disagreement over how to handle the case where the user supplied an empty list. At some point we'll probably put them back, but they're not there now. When they do come back, maybe we'll use `selfFoldl`. > > > > Thanks, > > > > -- Scott Out of curiosity -- what was the disagreement? Returning undefined seems like the natural choice since the result is, well, undefined in this case. Is the concern with the way undefined is sometimes quirky in javascript?
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-30 13:39 -0700 |
| Message-ID | <0eda5ddb-5a7a-4fa6-8d4c-219034645bcb@googlegroups.com> |
| In reply to | #24493 |
John C wrote:
> Scott Sauyet wrote:
>> The funny thing is that I'd forgotten we'd taken these out of the
>> library in response to a disagreement over how to handle the case
>> where the user supplied an empty list. At some point we'll probably
>> put them back, but they're not there now. When they do come back,
>> maybe we'll use `selfFoldl`.
(I'm sorry about the poor formatting earlier. The updated Google Groups
was one of the reasons I've been gone for a while. I'm sorry to see
that it's as bad as ever!)
> Out of curiosity -- what was the disagreement? Returning undefined
> seems like the natural choice since the result is, well, undefined
> in this case. Is the concern with the way undefined is sometimes
> quirky in javascript?
Then you will agree with my coauthor, who argued for the same thing.
We had a long discussion about this, captured here:
<https://github.com/CrossEye/ramda/issues/20>
The original implementation, following Haskell, raised an exception in
this case. My coauthor didn't like this, thinking that we should return
`undefined`. I, in turn, didn't like returning anything that might make
the user have to type-check her results. Neither of us was really
willing to budge, and as these were not very important to either of us,
it was easier to simply remove the functions and see if something didn't
settle out of it eventually. This was, I think, the only significant
disagreement we've had over the time we've spent on this.
Eventually, it came down to his preference list, which looked like this:
1. remove foldl1/foldr1 from the library
2. return undefined for empty list
3. throw exception
and mine, which looked like this:
1. throw exception
2. remove foldl1/foldr1 from the library
3. return undefined for empty list
At that point, it was pretty clear that the easiest thing was to remove
these functions. They are easy enough to add back if someone wants. And
maybe we will at some point.
-- Scott
[toc] | [prev] | [next] | [standalone]
| From | John C <rescattered@gmail.com> |
|---|---|
| Date | 2014-05-30 19:17 -0700 |
| Message-ID | <6adc900a-ed11-45f5-b7bf-413a2b5018a6@googlegroups.com> |
| In reply to | #24498 |
On Friday, May 30, 2014 4:39:21 PM UTC-4, Scott Sauyet wrote:
> John C wrote:
>
> > Scott Sauyet wrote:
>
> >> The funny thing is that I'd forgotten we'd taken these out of the
>
> >> library in response to a disagreement over how to handle the case
>
> >> where the user supplied an empty list. At some point we'll probably
>
> >> put them back, but they're not there now. When they do come back,
>
> >> maybe we'll use `selfFoldl`.
>
>
>
> (I'm sorry about the poor formatting earlier. The updated Google Groups
>
> was one of the reasons I've been gone for a while. I'm sorry to see
>
> that it's as bad as ever!)
>
>
>
> > Out of curiosity -- what was the disagreement? Returning undefined
>
> > seems like the natural choice since the result is, well, undefined
>
> > in this case. Is the concern with the way undefined is sometimes
>
> > quirky in javascript?
>
>
>
> Then you will agree with my coauthor, who argued for the same thing.
>
> We had a long discussion about this, captured here:
>
>
>
> <https://github.com/CrossEye/ramda/issues/20>
>
>
>
> The original implementation, following Haskell, raised an exception in
>
> this case. My coauthor didn't like this, thinking that we should return
>
> `undefined`. I, in turn, didn't like returning anything that might make
>
> the user have to type-check her results. Neither of us was really
>
> willing to budge, and as these were not very important to either of us,
>
> it was easier to simply remove the functions and see if something didn't
>
> settle out of it eventually. This was, I think, the only significant
>
> disagreement we've had over the time we've spent on this.
>
>
>
> Eventually, it came down to his preference list, which looked like this:
>
>
>
> 1. remove foldl1/foldr1 from the library
>
> 2. return undefined for empty list
>
> 3. throw exception
>
>
>
> and mine, which looked like this:
>
>
>
> 1. throw exception
>
> 2. remove foldl1/foldr1 from the library
>
> 3. return undefined for empty list
>
>
>
> At that point, it was pretty clear that the easiest thing was to remove
>
> these functions. They are easy enough to add back if someone wants. And
>
> maybe we will at some point.
>
>
>
> -- Scott
I guess I was thinking in terms of the Principle of Least Astonishment (POLA).
JavaScript already has some functional features, so I would think that
a library for functional programming in JavaScript should extend what is
already there rather than rewriting it. It should be possible to take
an existing program in JavaScript which has strong functional features
and somewhat easily rewrite it using the library. In particular -- code
which already uses JavaScript's reduce should be easily modified to run
using the new folding functions that you provide. Thus, I would expect
that selfFold would be more or less equivalent to:
function selfFold(f,xs)
{
return xs.slice(1).reduce(f,xs[0]);
}
with e.g. add(x,y) defined as {return x+y;} this yields
selfFold(add,[3,5,7]); // => 15, as expected
but we also have
selfFold(add,[]); // => undefined
which is also completely expected to a JavaScript programmer.
Thus *unless there is a compelling reason to do otherwise*, POLA would
suggest that an implementation of selfFold would return undefined on an
empty list.
On the other hand, I haven't thought about the issue much, and am open to
the claim that in e.g. the importance of having a consistent approach to error
handling across a library might outweigh POLA in this case.
[toc] | [prev] | [next] | [standalone]
| From | Scott Sauyet <scott.sauyet@gmail.com> |
|---|---|
| Date | 2014-05-31 09:52 -0700 |
| Message-ID | <f2386144-c7df-4280-8af9-9258919a9a66@googlegroups.com> |
| In reply to | #24501 |
John C wrote:
> Scott Sauyet wrote:
>> [ ... re: when foldl1/foldr1 is called with no accumulator ...]
>> The original implementation, following Haskell, raised an exception in
>> this case. My coauthor didn't like this, thinking that we should return
>> `undefined`. I, in turn, didn't like returning anything that might make
>> the user have to type-check her results.
> I guess I was thinking in terms of the Principle of Least
> Astonishment (POLA). JavaScript already has some functional
> features, so I would think that a library for functional programming
> in JavaScript should extend what is already there rather than
> rewriting it.
I'm afraid that we might then be disappointing you. For the most
part, the array processing functions are all hand-written.
(Christoph Becker notes some exceptions earlier in this thread.) We
do this for various reasons, but the biggest one is to be in control
of the API. On the other hand, we do have a function `invoker`
which turns a method on an object (usually a prototype) into a plain
function, and we use it to expose much of the String.prototype as
functions. For instance,
ramda.substring = invoker("substring", String.prototype);
which we could use like this:
map(substring(0, 2), ["Fools", "rush", "in"]);
//=> ["Fo", "ru", "in"]
So in one sense it sounds as though we're being inconsistent. But
there are problems combining the native functional array methods
with other built-in functions. The classic example is
["1.1", "2.2", "3.3"].map(parseFloat); //=> [1.1, 2.2, 3.3]
["1", "2", "3"].map(parseInt); //=> [1, NaN, NaN]
The problem is that the native `Array.prototype.map` passes
additional arguments to its callback functions: the index and the
entire list. This isn't a problem for `parseFloat`, which only uses
the first parameter. But `parseInt` takes an optional second
parameter, the radix:
parseInt("1", 0) //=> parseInt("1", 10) => 1
parseInt("2", 1) //=> NaN
parseInt("3", 2) //=> NaN
For our purposes, we want to be able to do this:
map(parseInt, ["1", "2", "3"]); //=> [1, 2, 3]
or maybe this, if we want to be careful about the radix:
map(flip(parseInt)(10), ["1", "2", "3"]); //=> [1, 2, 3]
so our `map` (similarly our `filter`, `foldl/foldr`, `forEach`,
etc.) only accept the element. Recognizing that there are
legitimate uses for the multiple parameter calls, we do offer
variants that pass them along, but they're not the baseline calls:
map.idx(fn, list); // callback: fn(element, index, list)
> It should be possible to take an existing program in JavaScript
> which has strong functional features and somewhat easily rewrite it
> using the library. In particular -- code which already uses
> JavaScript's reduce should be easily modified to run using the new
> folding functions that you provide. Thus, I would expect that
> selfFold would be more or less equivalent to:
> function selfFold(f,xs)
> {
> return xs.slice(1).reduce(f,xs[0]);
> }
Minus the error-checking, it was, in fact, written like this:
ramda.foldl1 = curry(function (fn, list) {
return foldl(fn, head(list), tail(list));
}
which isn't all that different, but depends on our foldl function
rather than the native one.
> with e.g. add(x,y) defined as {return x+y;} this yields
>
> selfFold(add,[3,5,7]); // => 15, as expected
>
> but we also have
>
> selfFold(add,[]); // => undefined
Yes. That was part of our discussion. And it's almost compelling
to me. But not quite. If the user of foldl uses a function that
always returns an element with a certain interface and supplies one
like that as the accumulator, then foldl will always return one with
that same interface, and the user has to do no further type-checking
on the result. If she were to switch to foldl1, and she happens to
supply an empty list, obviously she cannot get back that interface
(for how would we call her function?) So then we're left with three
real possibilities: return something else, return nothing, or throw
an error. Throwing something else -- even null -- seems pretty
crazy. You're argument for returning nothing/undefined is
reasonable. Mine is that this is essentially an unrecoverable error
unless we as developers of the library want to insist that users
wrap type-checking around the results of calling selfFold; I think
it's also a reasonable argument for throwing an error in this
circumstance.
> which is also completely expected to a JavaScript programmer. Thus
> *unless there is a compelling reason to do otherwise*, POLA would
> suggest that an implementation of selfFold would return undefined on
> an empty list.
I'm not sure that an argument about one possible implementation of
an idea can really carry the weight of the Principle of Least
Astonishment.
Here is another perfectly reasonable version of selfFold:
function selfFold(f,xs) {
return xs.reduce(f);
}
`Array.prototype.reduce` takes a function and *optionally* the
initial accumulator value. If one isn't supplied, it takes the
first item in the list as its value, and starts processing with
the second one. This might be an even more obvious way to use
the native version than your suggestion. But note:
[1, 2, 3].reduce(add); //=> 6
[1].reduce(add); //=> 1
[].reduce(add); //=> TypeError: Reduce of empty array with
// no initial value
I didn't think of this argument in the discussion I had with Ramda's
coauthor, but it's an interesting point: It's not just how Haskell
does it; it's also the native JS answer.
> On the other hand, I haven't thought about the issue much, and am
> open to the claim that in e.g. the importance of having a consistent
> approach to error handling across a library might outweigh POLA in
> this case.
My point wasn't about consistent error-handling. We really haven't
figured that out yet. My main concern was as a user of the library
to never have the library return bad data to me.
Thank you very much for your interesting feedback,
-- Scott
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.javascript
csiph-web