gyac6g
Last Updated: February 25, 2016
·
680
· caseykramer

Taking advantage of the laziness of Seq in F#

Its worth remembering that the laziness that comes along with F#'s Seq<'a> data type (the IEnumerable<T> equivalent) has advantages beyond just creating infinite sequences.

When using Seq any transformations that you do the the sequence are inlined, so they occur sequentially for each element, rather than processing all the elements before moving on to the next step in the processing pipeline.

Example:
Lets take a simple numeric filter, which will only allow numbers divisible by 2:

let filter1 i = i % 2 = 0

And so we have another step in the process lets do the same thing for numbers divisible by 3:

let filter2 i = i % 3 = 0

Now, if you were to chain these together using List.filter like so:
[ 1 .. 20 ] |> List.filter filter1 |> List.filter filter2

What happens under the covers is that for each number in the list (1 through 20) filter 1 gets run, then the resulting list gets fed to filter 2, so the process is something like

1 % 2 = 0
2 % 2 = 0
3 % 2 = 0
4 % 2 = 0
...
20 % 2 = 0

Followed by

2 % 3 = 0
4 % 3 = 0
6 % 3 = 0
8 % 3 = 0
...
20 % 3 = 0

Yielding a final list of [ 6; 12; 18 ]

Now, if the same thing is done with a Seq (and the Seq.filter function) like so:
{ 1 .. 20 } |> Seq.filter filter1 |> Seq.filter filter2
You get the following:

1 % 2 = 0
2 % 2 = 0
2 % 3 = 0
3 % 2 = 0
4 % 2 = 0
4 % 3 = 0
...

This also works if your source is a List, and you use the Seq functions like:
[ 1 .. 20 ] |> Seq.filter filter1 |> Seq.filter filter2

Also, the same thing happens in C# when your using IEnumerables and iterators