Kev*_*Won 5 evaluation f# eager lazy-evaluation
我遇到了我的代码中的一个错误,这让我觉得我并不真正理解有关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
Run Code Online (Sandbox Code Playgroud)
当我在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
Run Code Online (Sandbox Code Playgroud)
这让我觉得这getStringFromFile
是懒惰的评价 - 所以我完全糊涂了.我没有得到关于F#如何评估函数的信息.
Jul*_*iet 10
为了快速解释发生了什么,让我们从这里开始:
let getStringFromFile =
File.OpenRead("c:\\eo\\raw.txt")
|> fun s -> let r = new StreamReader(s)
let data = r.ReadToEnd
r.Close()
s.Close()
data
Run Code Online (Sandbox Code Playgroud)
您可以将函数的前两行重写为:
let s = File.OpenRead(@"c:\eo\raw.txt")
Run Code Online (Sandbox Code Playgroud)
接下来,您省略了此方法的括号:
let data = r.ReadToEnd
r.Close()
s.Close()
data
Run Code Online (Sandbox Code Playgroud)
结果,data
有类型unit -> string
.从函数返回此值时,整个结果为unit -> string
.但是看看在分配变量和返回变量之间会发生什么:你关闭了流.
最终结果,当用户调用该函数时,流已经关闭,导致您在上面看到的错误.
并且不要忘记通过声明use whatever = ...
而不是处理您的对象let whatever = ...
.
考虑到这一点,这是一个修复:
let getStringFromFile() =
use s = File.OpenRead(@"c:\eo\raw.txt")
use r = new StreamReader(s)
r.ReadToEnd()
Run Code Online (Sandbox Code Playgroud)