I was reading Choosing between collection functions on the fsharpforfunandprofit site, and he showed an example of how to avoid accessing a disposable resource after it had been disposed (Section 28, right at the end of the article).
He simulated a database with the following...
let dbConnection() =
printfn "Opening connection"
{ new System.IDisposable with
member this.Dispose() =
printfn "Disposing connection"
}
// Read some records from the database
let readCustomersFromDb conn n =
let makeCustomer i =
sprintf "Customer %d" i
seq {
for i = 1 to n do
let customer = makeCustomer i
printfn "Loading %s from the database" customer
yield customer
}
...and then showed how to avoid the problem by enumerating the sequence before returning it...
let readCustomers() =
use conn = dbConnection()
let results = readCustomersFromDb conn 2
results |> List.ofSeq
I was a bit confused by that last bit, as I thought we had a sequence, and wanted to convert it to a list. This is how it works in C#, which could be where I'm thinking wrongly. He seems to be taking a list and converting it to a sequence.
Anyway, I tried changing that last line to...
results |> Seq.toList
...and it worked just the same.
So, what's the difference between the two, and why do they do the same thing here? I thought sequences were non-enumerated, in which case I would have expected his original code not to have worked.
Both List.ofSeq
and Seq.toList
have type 'a seq -> 'a list
and indeed List.ofSeq
is defined as
let ofSeq source = Seq.toList source
(defined in the Microsoft.FSharp.Collections.List
module)
so indeed they are just the same.
As you get a list (which - unlike a seq
- is a strict structure in F#) all the elements of the sequence are evaluated to populate the list in memory - that's why you can use both functions to force the iteration of all the values.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With