fl

Functional lazy sequence operators

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
identity( value )

Returns value.

increment( value )

Returns value + 1.

decrement( value )

Returns value - 1.

isEven( value )

Returns value % 2 === 0.

isOdd( value )

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

sum( ...addends )

Returns the sum of 0 and zero or more addends.

multiply( ...factors )

Returns the product of 1 and zero or more factors.

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

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

complement( predicate )

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

complement( isEven )(3);
true
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( 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 ( valueindex ) {
  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( fn, sequence )

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

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.

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( ...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( ...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( ...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( ...values )
// >>> boolean 

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

apply( nondecreasing, 'bees' );  // >>> true 
Sequence().first()
// >>> * 
 
first( sequence )
// >>> * 

Returns the first element in sequence.

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

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

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 ).

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 ]

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 ]

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' ]

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 ]

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' ]

Performs a filter on the complement of the provided predicate.

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 ]

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 );
}

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 ]

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.

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 ]
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.

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.

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() );
[]

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' ]

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' ]

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 ] ]

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' ] ]
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` 

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' ]

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' ]