Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Immutable.js - lazy sequence

I recently heard about Facebook's Immutable.js library (https://github.com/facebook/immutable-js). I am confused about the following from their documentation:

var oddSquares = Immutable.Sequence(1,2,3,4,5,6,7,8)
  .filter(x => x % 2).map(x => x * x);
console.log(oddSquares.last());

In this example, no intermediate arrays are ever created, filter is only called twice, and map is only called once

How is filter called only twice, map once?

like image 777
tldr Avatar asked Sep 16 '14 17:09

tldr


People also ask

Is immutable js fast?

Immutable push is super fastjs is about 100x faster than push of native javascript . Note that when pushing an element to an immutable. js list, the list is not modified. A new list is returned with the element appended to it: this is how immutable collections work.

Is seq immutable?

Seq is immutable — Once a Seq is created, it cannot be changed, appended to, rearranged or otherwise modified.

How does immutable Javascript work?

Working with immutable objects A pure function has two properties that make it unique: The value it returns is dependent on the input passed. The returned value will not change as long as the inputs do not change. It does not change things outside of its scope.

Are Javascript maps immutable?

js provides many Persistent Immutable data structures including: List , Stack , Map , OrderedMap , Set , OrderedSet and Record .


1 Answers

Because of the logic of map and filter regarding lazy evaluation of sequences

map

last() called over a mapped sequence return the last() of the original sequence processed by the mapper function.

So for example:

 var mappedSequence = Immutable.Sequence(1,2,3,4,5,6,7,8).map(x => x * x);
 console.log(mappedSequence.last());

Will output 64 and will call map only once, because the only thing it does is get the last element of original sequence (8) and map it on x => x * x (resulting on 64)

filter

last() called over a filtered sequence, will reverse walk the sequence until it finds a value on sequnce matching the criteria. So, for example

 var mappedSequence = Immutable.Sequence(1,2,3,4,5,6,7,8).filter(x => x % 2);
 console.log(mappedSequence.last());

WIll output 7 and will call filter only twice, because it call the filter (x => x % 2) for 8 first, it returns 0 meaning false for javascript (so it should be filtered), and then call the filter function again to get 7 % 2 = 1 being true for javascript and returning that value as the last without calling filter functoin anymore.

As additional example to help understand:

 var mappedSequence = Immutable.Sequence(1,2,3,4,6,8).filter(x => x % 2);
 console.log(mappedSequence.last());

Would call the filter function four times, one for 8 (resulting false), one for 6 (false again), one for 4 (false again), and finally for 3 (finally resulting true)

Putting both pieces together

Your example:

var oddSquares = Immutable.Sequence(1,2,3,4,5,6,7,8)
   .filter(x => x % 2).map(x => x * x);
console.log(oddSquares.last());
  1. To get the last() value of mapped sequence, it first get the last() value of filtered sequence
  2. To get the last() value of filtered sequence, it first get the last() value of original sequence (8) and evaluate it agains the filter function ( x => x % 2 ), calling it for first time
  3. Since 8 % 2 = 0, it is false on JS and should be filtered, so, we move to the next value (7) and call the filter function again with this value
  4. 7 % 2 = 1, it is true on JS and should NOT be filtered, so, this is the last value of the filtered sequence
  5. We have the last value (7) required by the mapped sequence, so we call mapper function (x => x * x) only one time to get 49, the final result

At the end, we get called the filter function two times and the mapper function only once

like image 146
dseminara Avatar answered Sep 23 '22 15:09

dseminara