【问题标题】:F# lazy eval from stream reader?来自流阅读器的 F# 惰性评估?
【发布时间】:2010-09-15 17:27:49
【问题描述】:

我在我的代码中遇到了一个错误,这让我觉得我并不真正了解有关 F# 和惰性求值的一些细节。我知道 F# 急切地求值,因此对以下函数有些困惑:

// Open a file, then read from it. Close the file. return the data.
let getStringFromFile =  
    File.OpenRead("c:\\eo\\raw.txt")
    |> fun s -> let r = new StreamReader(s)
                let data = r.ReadToEnd
                r.Close()
                s.Close()
                data

当我在 FSI 中调用它时:

> let d = getStringFromFile();;

System.ObjectDisposedException: Cannot read from a closed TextReader.

at System.IO.__Error.ReaderClosed()
at System.IO.StreamReader.ReadToEnd()
at <StartupCode$FSI_0134>.$FSI_0134.main@()
Stopped due to error

这让我觉得 getStringFromFile 正在被懒惰地评估——所以我完全糊涂了。我不知道 F# 如何评估函数。

【问题讨论】:

    标签: f# evaluation lazy-evaluation eager


    【解决方案1】:

    为了快速解释正在发生的事情,让我们从这里开始:

    let getStringFromFile =  
        File.OpenRead("c:\\eo\\raw.txt")
        |> fun s -> let r = new StreamReader(s)
                    let data = r.ReadToEnd
                    r.Close()
                    s.Close()
                    data
    

    您可以将函数的前两行重写为:

    let s = File.OpenRead(@"c:\eo\raw.txt")
    

    接下来,您已经省略了此方法的括号:

                let data = r.ReadToEnd
                r.Close()
                s.Close()
                data
    

    因此,data 的类型为 unit -&gt; string。当你从你的函数返回这个值时,整个结果是unit -&gt; string。但是看看在分配变量和返回变量之间发生了什么:你关闭了流。

    最终结果,当用户调用该函数时,流已经关闭,导致您在上面看到的错误。

    不要忘记通过声明 use whatever = ... 而不是 let whatever = ... 来处理您的对象。

    考虑到这一点,这里有一个修复:

    let getStringFromFile() =  
        use s = File.OpenRead(@"c:\eo\raw.txt")
        use r = new StreamReader(s)
        r.ReadToEnd()
    

    【讨论】:

      【解决方案2】:

      你没有从你的文件中读取。您将StreamReader 实例的方法ReadToEnd 绑定到值data,然后在调用getStringFromFile() 时调用它。问题是此时流已关闭。

      我认为你错过了括号,这是正确的版本:

      // Open a file, then read from it. Close the file. return the data.
      let getStringFromFile =  
          File.OpenRead("c:\\eo\\raw.txt")
          |> fun s -> let r = new StreamReader(s)
                      let data = r.ReadToEnd()
                      r.Close()
                      s.Close()
                      data
      

      【讨论】:

        猜你喜欢
        • 2014-02-08
        • 2015-05-29
        • 1970-01-01
        • 1970-01-01
        • 2020-07-18
        • 2013-03-11
        • 2017-01-18
        • 2018-11-11
        相关资源
        最近更新 更多