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

2019-01-21 10:31发布

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.

标签: f#
5条回答
叼着烟拽天下
2楼-- · 2019-01-21 10:58

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.

查看更多
一夜七次
3楼-- · 2019-01-21 11:05

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>
查看更多
男人必须洒脱
4楼-- · 2019-01-21 11:05
    let lines = File.ReadLines(path)                

    // To check
    lines |> Seq.iter(fun x -> printfn  "%s" x) 
查看更多
一纸荒年 Trace。
5楼-- · 2019-01-21 11:06

On .NET 2/3 you can do:

let readLines filePath = File.ReadAllLines(filePath) |> Seq.cast<string>

and on .NET 4:

let readLines filePath = File.ReadLines(filePath);;
查看更多
Summer. ? 凉城
6楼-- · 2019-01-21 11:07
let readLines (filePath:string) = seq {
    use sr = new StreamReader (filePath)
    while not sr.EndOfStream do
        yield sr.ReadLine ()
}
查看更多
登录 后发表回答