rillet v1.15.0
rillet.js
Lazily evaluated ranges/streams/fp library built around ES6 generators
The Javascript Array class provide a number of methods that we typically associate with functional languages - filter/concat/forEach/etc. However, they're generally eagerly and exhaustively evaluated.
Rillet.js uses ES6 iterators to build these same methods in a lazily evaluated, streamable style, along the lines of .NET LINQ methods, Java 8 Streams, that kind of thing.
Installation
Rillet.js is available from npm
npm install rilletTrivial Example
const from = require('rillet').from;
const array_or_other_iterable = fn();
from(array_or_other_iterable).
filter(n => n > 100).
forEach(x => console.log(x));Rillet's Range objects are themselves iterable, so we could also write
const from = require('rillet').from;
const array_or_other_iterable = fn();
const filtered_iterable = from(array_or_other_iterable).filter(n => n > 100)
for (const x of filtered_iterable)
console.log(x)More Involved Example
const rillet = require('rillet');
const { of, zip, numbers } = rillet;
const fizzes = () => of('', '', 'Fizz').cycle();
const buzzes = () => of('', '', '', '', 'Buzz').cycle();
const words = () => zip(fizzes(), buzzes()).map(([f,b]) => `${f}${b}`)
const integers = () => numbers(1);
const fizzbuzz = (howMany) =>
zip(words(), integers()).
map(([w, n]) => !!w ? w : n).
take(howMany);
fizzbuzz(100).forEach(console.log);Methods
Creation methods
Range.from(iterable)creates a Range from an array-like or other iterable object (similar toArray.from())Range.of(...items)creates a Range with a variable number of arguments (similar toArray.of)Range.zip(...iterables)create a Range which returns a series of arrays, each containing the corresponding item from each iterables. E.g. givenp, q, ...return [p0, q0], [p1, q1], ... The sequence terminates when any of the iterables is exhausted.Range.numbers(start = 0, step = 1)creates a range of numbers,start,start + step,start + 2*step...Range.empty()create an empty Range - a new Range with no items. Directly equivalent tofrom([])orof()
The returned range is an iterable object, and so can be used in all the places where Javascript accepts an iterable - eg for/of loop, etc
Modifiers
Each modifier method returns a new Range which can be iterated on, or modified with further chained operations.
Range.prototype.filter(predicate)filters the returned sequence so only those elements that pass the test thatpredicateimplements.Range.prototype.map(fn)returns the result of applyingfnto each item in the sequenceRange.prototype.flatMap(fn)appliesfnto each item in the sequence, then flattens the result into a new sequenceRange.prototype.take(count)returns only the firstcountitems in the sequenceRange.prototype.takeWhile(predicate)returns items from the start of the sequence for as long as the predicate is trueRange.prototype.drop(count)discards the firstcountitems of the sequence, and returns the remainderRange.prototype.dropWhile(predicate)discards items from the start sequence for as long as the predicate is true, returning the remainderRange.prototype.concat(...items)creates a lazily concatenated iterable who's elements are all the elements of the sequence followed by all the elements of itemsRange.prototype.flat([depth])flattens any iterables in the sequence, down to thedepthgiven. Thedepthis optional and if omitted or is less than 1, it defaults to 1.Range.prototype.flatten()flattens any iterables in the sequence, creating a new stream which is entirely flatRange.prototype.distinct([fn])filters duplicates from the stream. The projectionfnis optional, defaulting to the identity function.Range.prototype.compact()removes all falsey values from the stream -0, false, null, undefined, '', NaNare all falsey.Range.prototype.cycle()returns an infinite sequence, looping over the items in the stream.Range.prototype.sort([comparator])orders the sequence using the optional comparator. (Note this comparator paramater here differs from that taken by Array.sort).
Terminal methods
A terminal method drains the range producing a single result.
Range.prototype.reduce(bifn, [initial])appliesfnagainst an accumulator and each element in the sequence, to reduce to a single value. The optionalinitialis used as the first argument to the first call offn. If noinitialis given, the first element in the sequence is used. Calling reduce on an empty sequence without an initial value will throw
Strictly speaking, reduce is all you need. However, for readability and expressiveness, rillet.js provides a number of methods implementing common terminal operations
Range.prototype.forEach(fn)appliesfnto each item in the sequence. Returns undefinedRange.prototype.count()returns the count of items in the sequenceRange.prototype.first()returns the first value in the sequence, or throws if the sequence is emptyRange.prototype.firstOrDefault(defaultValue)returns the first value in the sequence, or the defaultValue if the sequence is emptyRange.prototype.last()returns the last value in the sequence, or throws if the sequence is empty. Will never return if the sequence is unbounded.Range.prototype.lastOrDefault(defaultValue)returns the last value in the sequence, or the defaultValue if the sequence is empty.Range.prototype.max([comparator])finds the maximum item of the stream, according to the provided comparator. If no comparator is provided, it defaults to(item, currentmax) => item > currentmax. Returns undefined if the sequence is empty.Range.prototype.min([comparator])finds the minimum item of the stream, according to the provided comparator. If no comparator is provided, it defaults to(item, currentmax) => item < currentmax. Returns undefined if the sequence is empty.Range.prototype.sum()calculates the arithmetic sum of the items in the sequence, calling Number(x) on each item. The sum of the empty range is 0.Range.prototype.none(predicate)returns true if none of the items in the sequence match the predicate, and false otherwiseRange.prototype.every(predicate)returns true if all of the items in the sequence match the predicate, and false otherwiseRange.prototype.some(predicate)returns true if one or more of the items in the sequence match the predicate, and false otherwiseRange.prototype.join(separator)join all the items in the sequence into a string, using the provided separator. If the separator is not given, the items are separated with a comma.Range.prototype.toArray()gathers all the items in the sequence into an array.Range.prototype.toSet()gathers all the items in the sequence into a Set.
In the notes above,
fnhas the formx => operation(x), where operation returns a valuebifnhas the form(x,y) => operation(x, y), where operation returns a valuepredicatehas the formx => test(x), where test returns a booleancomparatorhas the form(x,y) => compare(x, y), where compare returns true if the comparison of x and y succeeds. E.g. a comparator functionless_then(x, y)would return true if x was less that y, and false otherwise.- where a method has the same name and form as a method on Array, it will exhibit the same behaviour
Name
A rillet is small rill. What's a rill? A very small brook. A brook? It's a small stream.
Every other stream related name was already taken on npm and this library is only a very small library, hence rillet.
License
Copyright (c) 2017,2024 JezUK Ltd
Licensed under the terms of the MIT License.
11 months ago
11 months ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago