如何使用F#中的let创建新范围?

Mic*_*ski 6 syntax f#

我试图在F#中初始化一个XmlDocument,而不会污染全局命名空间 - 我唯一的功能背景来自LISP,可以使用"let"创建一个新的范围.我想出了这个:

let doc = 
    let reader = new XmlTextReader("url")
    let doc = new XmlDocument()
    doc.Load(reader)
    doc
Run Code Online (Sandbox Code Playgroud)

当我的第一个解决方案不起作用时,我感到非常惊讶:

let doc = new XmlDocument() in
    let reader = new XmlTextReader("url");
    doc.Load(reader)

print_any reader.ToString // Still in scope!
Run Code Online (Sandbox Code Playgroud)

做我想要的首选方式是什么?

Tom*_*cek 4

似乎当您使用“let .. in”时,您可以覆盖默认的“#light”设置,即空白很重要,所以我想这就是这种情况下发生的情况以及为什么您没有收到任何警告/错误第二种情况(您添加了“in”,因此编译器认为您想要显式指定范围)。看起来有点奇怪,所以这可能是一个错误。我相信 F# 团队的 Brian 很快就会回答这个疑问:-)。

无论如何,我认为编译器将您的第二个示例视为(使用更容易编译的示例):

open System

let ar = new ResizeArray<_>() in
let rnd = new Random();    
ar.Add(rnd.Next())

printfn "%A" (rnd.Next())
Run Code Online (Sandbox Code Playgroud)

如果添加括号并编写如下内容,则可以强制它按照您的意愿对待它:

let ar = new ResizeArray<_>() in
    (let rnd = new Random() 
     ar.Add(rnd.Next()))

printfn "%A" (rnd.Next())
Run Code Online (Sandbox Code Playgroud)

通常,您可以使用括号在 F# 程序的任何位置指定作用域。例如你可以写:

let a = 1
(let a = a + 10
 printfn "%d" a)
printfn "%d" a
Run Code Online (Sandbox Code Playgroud)

此示例打印“10”,然后打印“1”。当然,这似乎不太实用,但是当使用use行为类似于let, 但适用于IDisposable对象并确保对象在离开作用域时被释放的关键字时,它很有用(这就像using在 C# 中一样):

let some = new Some()
(use file = new StreamReader(...)
 let txt = file.ReadToEnd()
 printfn "%s" txt)
doSomething() // continue, 'file' is now closed!
Run Code Online (Sandbox Code Playgroud)

编辑:我完全忘记提及重要的一点 - 第一种编写代码的方式对我来说似乎更自然(并且它充分利用了 F# 提供的“简单”#light 语法的好处),所以我更喜欢它:-) 。