Sequences and Laziness

Sequences are re-evaluated on each enumeration unless cached. Avoid multiple enumeration of expensive sequences (Seq.cache, or materialize with Seq.toList/Seq.toArray).

// seq<'T> = IEnumerable<'T>: lazy, evaluated on demand
let naturals = Seq.initInfinite id                         // 0, 1, 2, ...
naturals |> Seq.take 5 |> Seq.toList                       // [0; 1; 2; 3; 4]

let evens = seq { for i in 0 .. 100 do if i % 2 = 0 then yield i }
let lazyLog = seq { printfn "computing"; yield 42 }        // nothing printed until enumerated

// Sequence expressions with yield!
let rec fibs a b = seq {
    yield a
    yield! fibs b (a + b)
}
fibs 0 1 |> Seq.take 10 |> Seq.toList                      // [0; 1; 1; 2; 3; 5; 8; 13; 21; 34]

// Reading a file lazily
let lines = System.IO.File.ReadLines "big.log"             // lazy seq of lines
lines |> Seq.filter (fun l -> l.Contains "ERROR") |> Seq.length

// Seq module (mirrors List/Array): Seq.map, Seq.filter, Seq.fold, Seq.sum, Seq.head, Seq.tryFind,
// Seq.truncate, Seq.takeWhile, Seq.skipWhile; buffering ones: Seq.sortBy, Seq.groupBy, Seq.distinct
Seq.unfold (fun (a, b) -> Some (a, (b, a + b))) (0, 1) |> Seq.take 5   // 0 1 1 2 3
let cached = evens |> Seq.map (fun x -> x * x) |> Seq.cache            // memoize results
Seq.windowed 2 (seq { 1 .. 4 }) |> Seq.toList                          // [[|1; 2|]; 
…