Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
379 lines (257 sloc) 7.99 KB

Immutable lists

An immutable list is a list that has a head element and a tail. A tail is another list. The empty list is represented by the Nil constructor. An immutable list is also known as a "cons" list. Whenever an element is added to the list a new list is created which is essentially a new head with a pointer to the existing list.

Constructors

List();
// => Nil

List('a');
// => List('a')

List('a', List('b', List('c')));
// => List('a', 'b', 'c')

List.of('a')
List.unit('a')
List.pure('a')
// => List('a');

List.fromArray(['a', 'b', 'c']);
// => List('a', 'b', 'c')

There is also List.from that accepts anything implementing iterable pattern:

const unique = new Set(['a', 'b', 'a', 'b', 'c', 'c', 'a']);
List.from(unique);
// => List('a', 'b', 'c')

Creating a list from a pimped array

A list can be created also with the pimped method on Array, available in monet-pimp.js.

const myList = [1,2,3].list()

which is equivalent to:

const myList = List(1, List(2, List(3, Nil)))

Methods

cons

List[A].cons(element: A): List[A]

cons will prepend the element to the front of the list and return a new list. The existing list remains unchanged. For example:

const newList = myList.cons(4)
// myList =>     List(1, 2, 3)
// newList => List(4, 1, 2, 3)

map

List[A].map(fn: A => B): List[B]

Maps the supplied function over the list.

const list = List.fromArray([1, 2, 3]).map(a => a + 1)
// list => List(2, 3, 4)

flatMap

Aliases: bind, chain

List[A].flatMap(fn: A => List[B]): List[B]

Maps the supplied function over the list and then flattens the returned list. The supplied function must return a new list.

head

List[A].head(): A

Returns the head of the list. For example:

List.fromArray([1,2,3]).head()
// => 1

headMaybe

List[A].headMaybe(): Maybe[A]

Returns the optional head of the list. For example:

List.fromArray([1, 2, 3]).headMaybe()
// => Some(1)

Nil.headMaybe()
// => None()

foldLeft

List[A].foldLeft(initialValue: B)(fn: (acc: B, element: A) => B): B

foldLeft takes an initial value and a function, and will 'reduce' the list to a single value. The supplied function takes an accumulator as its first argument and the current element in the list as its second. The returned value from the function will be passed into the accumulator on the subsequent pass.

For example, say you wanted to add up a list of integers, your initial value would be 0 and your function would return the sum of the accumulator and the passed in element.

List.fromArray([1, 2, 3, 4]).foldLeft(0)((acc, e) => e + acc)
// => 10

foldRight

List[A].foldRight(initialValue: B)(fn: (element: A, acc: B) => B): B

Performs a fold right across the list. Similar to foldLeft except the supplied function is first applied to the right most side of the list (and its arguments are swapped).

append

Alias: concat

List[A].append(list: List[A]) : List[A]

Will append the second list to the current list. Both list must be of the same type. For example:

const list1 = List.fromArray([1, 2, 3])
const list2 = List.fromArray([4, 5, 6])

list1.append(list2)
// => List(1, 2, 3, 4, 5, 6)

list2.append(list1)
// => List(4, 5, 6, 1, 2, 3)

filter

List[A].filter(op: A => Boolean): List[A]

Returns a new list, keeping only elements for which the predicate returns true.

filterNot

List[A].filterNot(op: A => Boolean): List[A]

Returns a new list, keeping only elements for which the predicate returns false.

contains

List[A].contains(val: A): Boolean

Returns true if the List contains the given value.

find

List[A].find(op: A => Boolean): Maybe[A]

Returns a Maybe containing the first element for which the predicate returns true, or None.

sequence

List[Monad[A]].sequence(Monad): Monad[List[A]]

Will sequence a list of monads. The signature above is slightly hard to represent, but this function will sequence a list of any type of monad, but you will need to supply the name of the monad you are sequencing.

Note: This version of sequence will only work with Monads that can cope with eager evaluations. For lazy monads such as IO and Reader please use lazySequence or the explicit versions, such as sequenceIO.

For example:

List.fromArray([Right(1), Left(2)]).sequence(Either)
// => Left(2)

List.fromArray([Right(1), Right(2)]).sequence(Either)
// => Right(List(1, 2))

List.fromArray([Some(1), Some(2)]).sequence(Maybe)
// => Some(List(1, 2))

List.fromArray([Some(1), None()]).sequence(Maybe)
// => None

Or you can use the convenience methods like sequenceMaybe or sequenceEither below. Note that since Validation is not a true monad it will not work as expected for this method; use sequenceValidation instead.

lazySequence UNIMPLEMENTED

List[Monad[A].lazySequence(Monad): Monad[List[A]]

This is the same as sequence except it caters for Monads that require laziness, such as IO and Reader.

sequenceMaybe

List[Maybe[A]].sequenceMaybe(): Maybe[List[A]]

Takes a list of Maybes and turns it into a Maybe List. If the list contains at least one None value then a None will be returned, otherwise a Some will be returned with a list of all the values.

For example:

List.fromArray([Some(1), Some(2), Some(3)]).sequenceMaybe()
// => Some(List(1,2,3)) <- That's an immutable list not an array

List.fromArray([Some(1), Some(2), None, Some(3), None]).sequenceMaybe()
// => None

This is the same as calling:

List.fromArray([Some(1), Some(2)]).sequence(Maybe)

sequenceEither

List[Either[E,A]].sequenceEither(): Either[E, List[A]]

This will sequence a List of Eithers stopping on the first Left that it finds. It will return either a List of the Right values or the first Left value it encounters. For example:

List.fromArray([Right(1), Right(2), Right(3)]).sequenceEither()
// => Right(List(1, 2, 3))

List.fromArray([Right(1), Left(2), Left(3)]).sequenceEither()
// => Left(2)

Note: Unlike sequenceValidation it does not accumulate the Left (or "failing") values, but rather stops execution and returns the first Left.

sequenceValidation

List[Validation[E,A]].sequenceValidation(): Validation[List[E], List[A]]

Takes a list of Validations and turns it into a Validation List. It will collect all the success values into a list on the Success side of the validation or it accumulates the errors on the Failure side, if there are any failures.

List.fromArray([
  Success("a"),
  Success("b"),
  Success("c")
]).sequenceValidation()
// => Success(List("a", "b", "c"))

List.fromArray([
  Success("a"),
  Success("b"),
  Fail("c"),
  Fail("d"),
  Success("e")
]).sequenceValidation()
// => Fail(List("c", "d"))

sequenceIO

List[IO[A]].sequenceIO(): IO[List[A]]

Will sequence a list of IO actions.

sequenceReader

List[Reader[A]].sequenceReader(): Reader[List[A]]

Will sequence a list of Readers.

reverse

List[A].reverse(): List[A]

Returns a new list reversed.

List.fromArray([1,2,3]).reverse()
// => List(3, 2, 1)

every

Alias: forall

List[A].every(val: A => Boolean): Boolean

exists

List[A].exists(val: A => Boolean): Boolean

forEach

List[A].forEach(A => ()): ()

Invoke a function applying a side-effect on each item in the list.

toArray

List[A].toArray(): Array[A]

toSet

List[A].toSet(): Set[A]

to

List[A].to(Iterable[A] => B): B

...and undocumented

  • equals
  • join
  • takeLeft
  • takeRight
  • ap
  • snoc
  • isNEL
  • size
  • tail
  • tails
  • flatten
  • flattenMaybe