npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fl

v0.1.1

Published

Functional lazy sequence operators

Downloads

174

Readme

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