【问题标题】:How to create a new scope using let in F#?如何在 F# 中使用 let 创建新范围?
【发布时间】:2009-03-24 00:37:19
【问题描述】:

我正在尝试在 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!

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

【问题讨论】:

  • 哇不错。如果 Brian 没有回答这个问题,您应该考虑将其发送到 fsbugs@microsoft.com。
  • 我打开了错误 4693。:) 避免在#light 代码中使用“let...in”。

标签: syntax f#


【解决方案1】:

似乎当您使用“let .. in”时,您可以覆盖默认的“#light”设置,即空格很重要,所以我想这就是在这种情况下发生的情况以及为什么您没有收到任何警告/error 在第二种情况下(您添加了“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”。当然,这似乎不太实用,但在使用行为类似于letuse 关键字时很有用,但适用于IDisposable 对象并确保对象在离开范围时被释放(这就像 C# 中的 using):

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

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

【讨论】:

    【解决方案2】:

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

    您可以阅读Expert F# 的一些示例,感受当代 F# 风格。

    还有 Don Syme 写的F# Formatting Conventions

    【讨论】:

    • 确实,使用 let .. in 和 #light 选项是不必要的,尽管查看规范它作为可选语法仍然有效。读者仍在范围内的事实对我来说似乎确实很奇怪。可能的错误,也许?
    • 在我看来,它看起来像一个错误。但他在那个例子中混合了很多:#light,';'运算符、缩进和'in'。 F# 的语法远非优雅,也不直观——合并 ML 和 .NET 留下了太多包袱......
    【解决方案3】:

    问题的一部分可能是“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 是毫无歉意的命令,您将不得不凑合。

    【讨论】:

      猜你喜欢
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      • 2013-12-27
      • 1970-01-01
      • 2015-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多