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

时间:2009-03-24 00:37:19

标签: syntax f#

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

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

当我的第一个解决方案无效时,我感到非常惊讶:

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

print_any reader.ToString // Still in scope!

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

3 个答案:

答案 0 :(得分:3)

似乎当你使用“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())

如果你添加括号并写下这样的内容,你可以强迫它按照你的意愿对待它:

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

printfn "%A" (rnd.Next())

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

let a = 1
(let a = a + 10
 printfn "%d" a)
printfn "%d" a

此示例打印“10”,然后打印“1”。当然,这似乎不太实用,但在使用行为类似use的{​​{1}}关键字时,它很有用,但适用于let个对象并确保对象是当它离开范围时处理(这与C#中的IDisposable一样):

using

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

答案 1 :(得分:2)

你的第一个例子似乎是Don Syme和其他F#爱好者采用的风格。混合#light和ML风格let .. in似乎不是一个好主意。

您可以阅读Expert F#中的一些样本,以了解当代F#风格。

Don Syme也写了F# Formatting Conventions

答案 2 :(得分:0)

问题的一部分可能是“let ... in ...”是一个表达式,而不是一个语句,所以在顶层使用这个结构并没有多大意义。例如,说什么意思:

let x = 1 in
  x - 5

在顶层?似乎编译器应该在顶层标记“let ... in ...”的任何使用作为错误。

另一个问题是XmlDocument API不是以函数式编写的(根本没有),这使得从F#使用它有点尴尬。我说你的第一次尝试就像你将要获得的一样好,但如果API允许更多的东西,那肯定会很好:

let doc =
  let reader = new XmlTextReader("url")
  reader.ReadAsDocument()

或者如果有一个XmlDocument的构造函数接受了XmlReader,但由于API无可挑剔,所以你必须要做。