You are previewing Programming F#.

Programming F#

Cover of Programming F# by Chris Smith Published by O'Reilly Media, Inc.
O'Reilly logo


The most common use of lazy evaluation is through the sequence or seq type in F#, which represents an ordered sequence of items, much like a List. The following snippet defines a sequence of five elements and iterates through them using the Seq.iter function. (Just like the List module, there is a whole slew of available functions to use on sequences.)

> let seqOfNumbers = seq { 1 .. 5 };;

val seqOfNumbers : seq<int>

> seqOfNumbers |> Seq.iter (printfn "%d");;
val it : unit = ()


The difference between a seq and a list is that only one element of a sequence exists in memory at any given time. seq is just an alias for the .NET interface System.Collections.Generic.IEnumerable<'a>.

So why have this limitation? Why have two types when you can just use a list? Because having all list contents in memory means you are resource-constrained. You can define an infinite sequence quite easily, but an infinite list would run out of memory. Also, with lists, you must know the value of each element ahead of time, whereas sequences can unfold dynamically (in so-called pull fashion).

Example 3-11 defines a sequence of all possible 32-bit integers represented as strings. It then tries to create an equivalent list, but fails due to memory.

Example 3-11. A sequence of all integers

> // Sequence of all integers
let allIntsSeq = seq { for i = 0 to System.Int32.MaxValue -> i };; val allIntsSeq : seq<int> > allIntsSeq;; val it : seq<int> = seq [0; 1; 2; 3; ...] > // List of all integers ...

The best content for your career. Discover unlimited learning on demand for around $1/day.