The following example is based on a snippet that produces functions that allow enumerating sequence values one by one.
Here printAreEqual ()
gives true, print2 ()
gives 12345678910, but print1 ()
gives 0000000000.
Why cannot the function returned by enumerate return the values of the sequence generated using yield?
open System.Linq
let enumerate (xs: seq<_>) =
use en = xs.GetEnumerator()
fun () ->
en.MoveNext() |> ignore
en.Current
let s1 = seq { for i in 1 .. 10 do yield i }
let s2 = seq { 1 .. 10 }
let f1 = s1 |> enumerate
let f2 = s2 |> enumerate
let printAreEqual () = Enumerable.SequenceEqual (s1, s2) |> printf "%b" // true
let print1 () = for i in 1 .. 10 do f1() |> printf "%i" // 0000000000
let print2 () = for i in 1 .. 10 do f2() |> printf "%i" // 12345678910
The use en = ...
in the enumerate
function is effectively doing this:
let enumerate (xs: seq<_>) =
let en = xs.GetEnumerator()
let f =
fun () ->
en.MoveNext() |> ignore
en.Current
en.Dispose()
f
You're always disposing of the enumerator before you start using it, so the behaviour is probably undefined in this situation and it doesn't matter why you get different results for two sequences with different implementations.
Fine-grained control of sequence enumeration is always tricky and it's hard to make helper functions for because of the mutable state.