node package manager

fl

fl.js

Functional lazy operators and sequences.

  • Uses standard Iterator protocol
  • Accepts ES6 generators as lazy sequences
  • Designed to collaborate with modules such as pim.js, which provides persistent immutable data structures

API

General value operators

identity

identity( value )

Returns value.

increment

increment( value )

Returns value + 1.

decrement

decrement( value )

Returns value - 1.

isEven

isEven( value )

Returns value % 2 === 0.

isOdd

isOdd( value )

Returns value % 2 === 1 || value % 2 === -1.

sum

sum( ...addends )

Returns the sum of 0 and zero or more addends.

multiply

multiply( ...factors )

Returns the product of 1 and zero or more factors.

toArray

Sequence().toArray()
// >>> array 
 
toArray( sequence )
// >>> array 

Iterates through a sequence and returns its elements in an array.

complement

complement( predicate )

Returns a function that returns the logical negation of the result of applying predicate.

complement( isEven )(3);
true

compose

compose( ...fns )

Returns the composition of a series of functions fns, such that compose(f,g,h)(x) is equivalent to f(g(h(x))).

partial

partial( fn, ...args )

Given a function fn and successive arguments args fewer in number than the expected number of parameters for fn, returns a function that will return the result of applying fn to the concatentation of args and its own arguments.

addFive = partial( sum, 5 );
addFive(2);
7
 
rest = partial( dropWhile, function ( value, index ) {
  return index < 1;
});
// >>> function 
 
toArray( rest( range(4) ) );
[ 1, 2, 3 ]
 
toArray( rest( function* () {
  yield 2; yield 4; yield 6; yield 8;
}));
[ 4, 6, 8 ]

apply

apply( fn, sequence )

Returns the result of applying fn with each element in sequence as arguments.

compare

The default comparator function used with sort. Determines the ordinal relation between arguments x and y.

compare( x, y )
// >>> number 

Returns 0 if x and y are of equal precedence, returns -1 if x precedes y, or returns 1 if y precedes x. If x and y are logical sequences, then the comparison is evaluated recursively over the respective elements of both sequences.

comparator

Creates a boolean valued comparison operator.

comparator( predicate )
// >>> function 

Returns a predicate that returns true if applying predicate to each adjacent pairing of its arguments also returns true, and returns false otherwise.

nonconsecutive = comparator( compare );
 
apply( nonconsecutive, 'fireman' );  // >>> true 
apply( nonconsecutive, 'balance' );  // >>> true 
apply( nonconsecutive, 'ladders' );  // >>> false 

increasing

increasing( ...values )
// >>> boolean 

Returns true if arguments are provided in a strictly increasing order (<) as determined by compare; otherwise returns false.

Logically equivalent to comparator( (x,y) => compare(x,y) < 0 ).

apply( increasing, [0,1,4,9] );  // >>> true 
apply( increasing, [1,1,2,3] );  // >>> false 
apply( increasing, 'gist' );     // >>> true 
apply( increasing, 'bees' );     // >>> false 
 
apply( increasing, Sequence.range().take(5) );
// >>> true 

decreasing

decreasing( ...values )
// >>> boolean 

Returns true if arguments are provided in a strictly decreasing order (>) as determined by compare; otherwise returns false.

apply( decreasing, [9,4,1,0] );  // >>> true 
apply( decreasing, [3,2,1,1] );  // >>> false 
apply( decreasing, 'wronged' );  // >>> true 
apply( decreasing, 'sniffed' );  // >>> false 

nonincreasing

nonincreasing( ...values )
// >>> boolean 

Returns true if arguments are provided in a monotonically decreasing order (>=) as determined by compare; otherwise returns false.

apply( nonincreasing, 'sniffed' );  // >>> true 

nondecreasing

nondecreasing( ...values )
// >>> boolean 

Returns true if arguments are provided in a monotonically increasing order (<=) as determined by compare; otherwise returns false.

apply( nondecreasing, 'bees' );  // >>> true 

Sequential functions

first

Sequence().first()
// >>> * 
 
first( sequence )
// >>> * 

Returns the first element in sequence.

first( range(4) );
0
 
first([]);
undefined

Logically equivalent to take( 1, sequence )().next().value.

rest

Sequence().rest()
// >>> Sequence 
 
rest( sequence )
// >>> function 

Returns a logical sequence of the elements that follow the first element of sequence.

toArray( rest([ 0, 1, 2, 3 ]) );
[ 1, 2, 3 ]
 
toArray( rest([ 1 ]) );
[]
 
toArray( rest( [] ) );
[]
 
Sequence.range( 3, Infinity ).rest().take(4).toArray();
[ 4, 5, 6, 7 ]

Logically equivalent to drop( 1, sequence ).

range

Defines a sequence of numbers from start up to but excluding end in increments of step.

Sequence.range()
Sequence.range( end )
Sequence.range( start, end )
Sequence.range( start, end, step )
// >>> Sequence 
 
range()
range( end )
range( start, end )
range( start, end, step )
// >>> function 

Defaults for arguments not provided are: start = 0, end = Infinity, step = 1.

Returns a Sequence or sequence generator function.

toArray( range(4) );
[ 0, 1, 2, 3 ]
 
toArray( take( 5, range() ) );
[ 0, 1, 2, 3, 4 ]
 
toArray( range(-5) );
[]
 
toArray( range(3,9,2) );
[ 3, 5, 7 ]

iterate

Given a nominally pure function f and seed value x, defines an infinite sequence of x, f(x), f(f(x)), etc.

Sequence.iterate( fn, seed )
// >>> Sequence 
 
iterate( fn, seed )
// >>> function 

Returns a Sequence or sequence generator function.

toArray( take( 5, iterate( increment, 42 ) ) );
[ 42, 43, 44, 45, 46 ]

repeat

Given a value x, defines a repeating infinite sequence of x, or a finite sequence of x repeated up to limit times.

Sequence.repeat( value )
Sequence.repeat( value, limit )
// >>> Sequence 
 
repeat( value )
repeat( value, limit )
// >>> function 

Returns a Sequence or sequence generator function.

toArray( take( 5, repeat(42) ) );
[ 42, 42, 42, 42, 42 ]
 
Sequence.repeat( 'foo', 5 );
[ 'foo', 'foo', 'foo', 'foo', 'foo' ]

cycle

Defines an infinite sequence that repeats the items in sequence indefinitely.

Sequence.cycle()
// >>> Sequence 
 
cycle( sequence )
// >>> function 

Returns a Sequence or sequence generator function.

toArray( take( 10, cycle([3,4,5,6]) ) );
[ 3, 4, 5, 6, 3, 4, 5, 6, 3, 4 ]
 
Sequence([3,4,5,6]).take(10).toArray();
[ 3, 4, 5, 6, 3, 4, 5, 6, 3, 4 ]

filter

Applies a nominally pure predicate to each item in sequence and keeps those items for which predicate returns logical true.

Sequence().filter( predicate )
// >>> Sequence 
 
filter( predicate, sequence )
// >>> function 

Returns a Sequence, or sequence generator function, consisting of each element x in this or sequence for which the expression !!predicate(x) would equal true.

Sequence(["all", "your", "base", "are", "belong"]).filter( function (word) {
  return word.length < 4;
});
[ 'all', 'are' ]

remove

Performs a filter on the complement of the provided predicate.

map

Applies fn to successive items of one or more sequences.

Sequence().map( fn, ...sequences )
// >>> Sequence 
 
map( fn, sequence, ...sequences )
// >>> function 

The arity of fn should correspond with the number of sequences to be mapped.

Returns a Sequence, or sequence generator function, consisting of the result of applying fn to successive items taken from sequence and any additional sequences, in parallel, until any of sequence or sequences is exhausted.

toArray( map( increment, [1,2,3] ) );
[ 2, 3, 4 ]
 
Sequence([1,2,3]).map( increment ).toArray();
[ 2, 3, 4 ]
 
toArray( map( sum, [1,2,3], [10,20,30] ) );
[ 11, 22, 33 ]
 
Sequence([1,2,3]).map( sum, [10,20,30], [100,200,300] ).toArray();
[ 111, 222, 333 ]
 
Sequence([1,2,3]).map( sum, [10,20] ).toArray();
[ 11, 22 ]
 
Sequence( iterate increment, 1 ).map( sum, range(10,50,10) ).toArray();
[ 11, 22, 33, 44 ]

reduce

Iteratively calls fn, with two arguments:

  1. seed on the first iteration; thereafter, the result of the previous iteration

  2. each successive value in sequence.

If no seed is provided, the first value of the sequence is used as the seed and reduction proceeds on the remainder of the sequence.

Sequence().reduce( fn, seed )
Sequence().reduce( fn )
// >>> * 
 
reduce( fn, seed, sequence )
reduce( fn, sequence )
// >>> * 

Returns the result of the final iteration of fn. If the length of sequence is zero, returns the result of calling fn with no arguments. If the length of sequence is 1, the single element of sequence is returned.

function factorial (n) {
  return Sequence.range(n).map( increment ).reduce( multiply );
}

reductions

Produces a sequence of the intermediate values in a reduce operation.

Sequence().reductions( fn, seed )
Sequence().reductions( fn )
// >>> Sequence 
 
reductions( fn, seed, sequence )
reductions( fn, sequence )
// >>> function 

Returns a Sequence, or sequence generator function, of reductions.

Sequence.range(1,10).reductions( multiply ).toArray();
[ 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 ]
 
function factorialSequence (n) {
  return Sequence.range(n).map( increment ).reductions( multiply );
}
factorialSequence(10).toArray();
[ 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800 ]

take

Defines a sequence of up to amount items taken successively from sequence, or

Sequence().take( amount )
// >>> Sequence 
 
take( amount, sequence )
// >>> function 

Returns a Sequence or sequence generator function.

takeWhile

Defines a sequence of items taken successively from sequence so long as the expression !!predicate( item ) remains equal to true.

Sequence().takeWhile( predicate )
// >>> Sequence 
 
takeWhile( predicate, sequence )
// >>> function 

Returns a Sequence or sequence generator function.

Sequence
  .range()
  .takeWhile( function (x) {
    return Math.log(x) < 1;
  })
  .toArray();
[ 0, 1, 2 ]

drop

Sequence().drop( amount )
// >>> Sequence 
 
drop( amount, sequence )
// >>> function 

Returns a sequence of the items in sequence that would be excluded from the subsequence returned by an equivalent take operation.

dropWhile

Sequence().dropWhile( predicate )
// >>> Sequence 
 
dropWhile( predicate, sequence )
// >>> function 

Returns a sequence of the items in sequence that would be excluded from the subsequences returned by an equivalent takeWhile operation.

concat

Concatenates sequences.

Sequence().concat( ...sequences )
// >>> Sequence 
 
concat( sequence, ...sequences )
// >>> function 

Returns a single Sequence, or a sequence generator function, that is the concatentation of each sequence in the order they are provided.

Sequence.range(3).concat( range(5) ).toArray();
[ 0, 1, 2, 0, 1, 2, 3, 4 ]
 
Sequence('abc').concat('def', 'ghi').toArray();
[ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ]
 
toArray( concat() );
[]

splitAt

Divides a sequence into two sequences, where the first contains the first n elements of sequence, and the second contains the remaining elements of sequence.

Sequence().splitAt( n )
// >>> array 
 
splitAt( n, sequence )
// >>> array 

Returns a two-element array containing both partitions of sequence.

Sequence('qwerty')
  .splitAt(4)
  .map( Sequence )
  .map( function (s) {
    return s.toArray().join('');
  });
[ 'quer', 'ty' ]

splitWith

Divides a sequence into two sequences, where the first contains elements, starting from the head of sequence, that return logical true when predicate is applied to the element.

Sequence().splitWith( predicate )
// >>> array 
 
splitWith( predicate, sequence )
// >>> array 

Returns a two-element array containing both partitions of sequence.

function isConsonant (char) {
  return /[^aeiouy]/i.test(char);
}
Sequence('schtick')
  .splitWith( isConsonant )
  .map( Sequence )
  .map( function (s) {
    return s.toArray().join('');
  });
[ 'scht', 'ick' ]

partition

Partitions sequence into subsequences of size elements at offsets stride elements apart, where stride defaults to size such that partitions do not overlap. If the final partition is shorter than size, then: if a padding sequence is provided, that partition is filled with elements from padding until it grows to size; if no padding exists, the short partition is dropped.

Sequence().partition( size, stride, padding )
Sequence().partition( size, stride )
Sequence().partition( size )
// >>> Sequence 
 
partition( size, stride, padding, sequence )
partition( size, stride, sequence )
partition( size, sequence )
// >>> function 

Returns a Sequence of partitions, or a sequence generator function that returns an iterator over the partitions, where each partition is itself a sequence generator function that returns an iterator over the elements of the partition.

Sequence.range(12).partition(4).map( toArray ).toArray();
[ [ 0, 1, 2, 3 ], [ 4, 5, 6, 7 ], [ 8, 9, 10, 11 ] ]
 
Sequence.range(11).partition(4).map( toArray ).toArray();
[ [ 0, 1, 2, 3 ], [ 4, 5, 6, 7 ] ]
 
Sequence.range(16).partition(4,6).map( toArray ).toArray();
[ [ 0, 1, 2, 3 ], [ 6, 7, 8, 9 ], [ 12, 13, 14, 15 ] ]
 
Sequence.range(14).partition(4, 6, ['a']).map( toArray ).toArray();
[ [ 0, 1, 2, 3 ], [ 6, 7, 8, 9 ], [ 12, 13, 'a' ] ]
 
Sequence.range(14).partition(4, 6, 'abc').map( toArray ).toArray();
[ [ 0, 1, 2, 3 ], [ 6, 7, 8, 9 ], [ 12, 13, 'a', 'b' ] ]
 
Sequence.range(4).partition(10).map( toArray ).toArray();
[]
 
Sequence.range(4).partition(10,10,[]).map( toArray ).toArray();
[ [ 0, 1, 2, 3 ] ]

partitionBy

Applies fn to each value in sequence, partitioning it into subsequences each time fn returns a new value.

Sequence().partitionBy( fn )
// >>> Sequence 
 
partitionBy( fn, sequence )
// >>> function 

Returns a Sequence of partitions, or a sequence generator function that returns an iterator over the partitions, where each partition is itself a sequence generator function that returns an iterator over the elements of the partition.

Sequence
  .range(1,6)
  .partitionBy( function (x) { return x === 3 } )
  .map( toArray )
  .toArray();
[ [ 1, 2 ], [ 3 ], [ 4, 5 ] ]
 
 
Sequence( [1,1,1,2,2,3,3] ).partitionBy( isOdd ).map( toArray ).toArray();
[ [ 1, 1, 1 ], [ 2, 2 ], [ 3, 3 ] ]
 
Sequence( [1,1,1,2,2,3,3] ).partitionBy( isEven ).map( toArray ).toArray();
[ [ 1, 1, 1 ], [ 2, 2 ], [ 3, 3 ] ]
 
 
Sequence("Leeeeeerrrrooyyy")
  .partitionBy( identity )
  .map( toArray )
  .toArray();
[ [ 'L' ],
  [ 'e', 'e', 'e', 'e', 'e', 'e' ],
  [ 'r', 'r', 'r', 'r' ],
  [ 'o', 'o' ],
  [ 'y', 'y', 'y' ] ]

interleave

Sequence.interleave( ...sequences )
Sequence().interleave( ...sequences )
// >>> Sequence 
 
interleave( ...sequences )
// >>> function 

Given one or more sequences, defines a sequence consisting of the first item from each of the sequences, continuing with the second item from each of the sequences, etc., stopping after any one of the sequences has been exhausted.

Sequence.interleave( range(), [7,8,9] ).toArray();
[ 0, 7, 1, 8, 2, 9 ]  // no `3` 

interpose

Places a value between each element in a sequence.

Sequence().interpose( value )
// >>> Sequence 
 
interpose( value, sequence )
// >>> function 

Returns a new logical sequence containing the value interposed within the elements of the original sequence.

Sequence("dmtr").interpose('e').toArray();
[ 'd', 'e', 'm', 'e', 't', 'e', 'r' ]

sort

Sorts the contents of a finite, homogeneous logical sequence, as directed by a pure function comparator if provided, or by compare otherwise. Elements of the sequence which are themselves sequences are compared by recursively comparing the respective elements of both nested sequences.

Sequence().sort( comparator )
Sequence().sort()
// >>> Sequence 
 
sort( comparator, sequence )
sort( sequence )
// >>> function 

Returns a new logical sequence containing the sorted elements of the original sequence.

Sequence([ 'abduct', 'abacus', 'abated', 'abate' ])
  .map( Sequence )
  .sort( compare )
  .map( toArray )
  .map( function (a) { return a.join(''); } )
  .toArray();
[ 'abacus', 'abate', 'abated', 'abduct' ]

👋