13

我编写了这段代码,它可以在 VS.NET 2010 中完美编译和运行

module ConfigHandler
open System
open System.Xml
open System.Configuration

let GetConnectionString (key : string) =
  ConfigurationManager.ConnectionStrings.Item(key).ConnectionString

但是,当我执行 control + A 和 Alt + Enter 将其发送到 FSI 时,出现错误

ConfigHandler.fs(2,1):错误 FS0010:定义中结构化构造的意外开始。应为“=”或其他标记。

好的。

所以我将代码更改为

module ConfigHandler =
  open System
  open System.Xml
  open System.Configuration

  let GetConnectionString (key : string) =
    ConfigurationManager.ConnectionStrings.Item(key).ConnectionString

现在 Control + A, Alt + Enter 成功了,我 FSI 很好地告诉我

模块 ConfigHandler = begin val GetConnectionString : string -> string end

但是现在如果我尝试在 VS.NET 2010 中编译我的代码,我会收到一条错误消息

库或多文件应用程序中的文件必须以命名空间或模块声明开头,例如“namespace SomeNamespace.SubNamespace”或“module SomeNamespace.SomeModule”

我怎么能两者兼得?能够在 VS.NET 中编译以及将模块发送到 FSI 的能力?

4

2 回答 2

20

您的两个代码片段之间存在微小但至关重要的差异,这应该归咎于这里。

F# 有两种方法来声明module. 第一个是“顶级模块”,声明如下:

module MyModule
// ... code goes here

声明模块的另一种方法是作为“本地模块”,如下所示:

module MyModule =
    // ... code goes here

“顶级”和“本地”声明之间的主要区别在于,本地声明后跟一个=符号,并且“本地”模块中的代码必须缩进。

您收到ConfigHandler.fs(2,1): error FS0010: Unexpected start of structured construct in definition. Expected '=' or other token.第一个代码段消息的原因是您不能在fsi.

当您将=符号添加到模块定义时,它从顶级模块更改为本地模块。从那里,您得到了错误Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule',因为本地模块必须嵌套在顶级模块或命名空间中。fsi不允许您定义命名空间(或顶级模块),因此如果您想将整个文件复制粘贴到fsi唯一可行的方法是使用 @pad 提到的编译指令。否则,您可以简单地将本地模块定义(不包含命名空间)复制粘贴到其中fsi,它们应该可以按预期工作。

参考: MSDN 上的模块 (F#)

于 2012-08-28T13:12:09.917 回答
10

常见的解决方案是保留第一个示例并创建一个fsx引用该模块的文件:

#load "ConfigHandler.fs"

您可以加载多个模块并为实验编写管道代码。

如果你真的想ConfigHandler.fs直接加载到 F# Interactive,你可以使用INTERACTIVE符号和编译器指令

#if INTERACTIVE
#else
module ConfigHandler
#endif

它适用于 fsi 和 fsc。

于 2012-08-28T09:30:11.130 回答