How read a file into a seq of lines in F#

This is C# version:

public static IEnumerable<string> ReadLinesEnumerable(string path) {
  using ( var reader = new StreamReader(path) ) {
    var line = reader.ReadLine();
    while ( line != null ) {
      yield return line;
      line = reader.ReadLine();
    }
  }
}

But directly translating needs a mutable variable.


If you're using .NET 4.0, you can just use File.ReadLines.

> let readLines filePath = System.IO.File.ReadLines(filePath);;

val readLines : string -> seq<string>

open System.IO

let readLines (filePath:string) = seq {
    use sr = new StreamReader (filePath)
    while not sr.EndOfStream do
        yield sr.ReadLine ()
}

To answer the question whether there is a library function for encapsulating this pattern - there isn't a function exactly for this, but there is a function that allows you to generate sequence from some state called Seq.unfold. You can use it to implement the functionality above like this:

new StreamReader(filePath) |> Seq.unfold (fun sr -> 
  match sr.ReadLine() with
  | null -> sr.Dispose(); None 
  | str -> Some(str, sr))

The sr value represents the stream reader and is passed as the state. As long as it gives you non-null values, you can return Some containing an element to generate and the state (which could change if you wanted). When it reads null, we dispose it and return None to end the sequence. This isn't a direct equivalent, because it doesn't properly dispose StreamReader when an exception is thrown.

In this case, I would definitely use sequence expression (which is more elegant and more readable in most of the cases), but it's useful to know that it could be also written using a higher-order function.


    let lines = File.ReadLines(path)                

    // To check
    lines |> Seq.iter(fun x -> printfn  "%s" x)