F#、命名空间、模块、fs和fsx

27

我知道关于F#中模块和命名空间的其他问题,但它们现在对我没有帮助。

我有一个项目,其中包含

Utilities.fs

namespace Company.Project.Namespace
module Utilities = 
     //stuff here

Functions.fs

namespace Company.Project.Namespace
open Utilities

module Functions = 
     //stuff here

我正在尝试在fsx中对它们进行测试:

#load "Utilities.fs"
#load "Functions.fs"

当我尝试使用Alt-Enter将其发送到FSI时,它给了我一个error FS0039: The namespace or module 'Utilities' is not defined的错误。我已经尝试在脚本文件顶部添加相同的命名空间,但它不喜欢那样做。奇怪的是后台编译器没有对我发出警告。这似乎有效,但这是正确的方法吗?
#load "Utilities.fs"
open Company.Project.Namespace
#load "Functions.fs"

是否有一个“参考”FSharp项目,其中包含如何集成所有这些东西的示例:命名空间、模块、类、脚本文件、测试等等?

2个回答

9

我不是FSI的专家,但一些实验表明,命名空间仅由#load声明支持(而不是通过典型的交互方式 - 通过Alt-Enter将命名空间声明组发送到VFSI无效),不同的交互方式会贡献不同的“实例”。例如,对于代码文件:

namespace Foo

type Bar() =
    member this.Qux() = printfn "hi"

namespace Other

type Whatever() = class end

namespace Foo

module M =
    let bar = new Bar()
    bar.Qux()

如果我多次#load它,我会得到例如:

> [Loading C:\Program.fs]
hi

namespace FSI_0002.Foo
  type Bar =
    class
      new : unit -> Bar
      member Qux : unit -> unit
    end
namespace FSI_0002.Other
  type Whatever =
    class
      new : unit -> Whatever
    end
namespace FSI_0002.Foo
  val bar : Bar

> #load @"C:\Program.fs";;
> [Loading C:\Program.fs]
hi

namespace FSI_0003.Foo
  type Bar =
    class
      new : unit -> Bar
      member Qux : unit -> unit
    end
namespace FSI_0003.Other
  type Whatever =
    class
      new : unit -> Whatever
    end
namespace FSI_0003.Foo
  val bar : Bar

> new Foo.Bar();;
> val it : Foo.Bar = FSI_0003.Foo.Bar

请注意,FSI_0003.Foo.Bar似乎掩盖了FSI_0002版本。
因此,我认为F#规范的这部分应该是:

Within a namespace declaration group, the namespace itself is implicitly opened if any preceding namespace declaration groups or referenced assemblies contribute to this namespace, e.g.

namespace MyCompany.MyLibrary 

   module Values1 = 
      let x = 1

namespace MyCompany.MyLibrary 

   // Implicit open of MyCompany.MyLibrary bringing Values1 into scope

   module Values2 = 
      let x = Values1.x

However this only opens the namespace as constituted by preceding namespace declaration groups.

由于FSI对命名空间的理解有限,因此不会与FSI互动。具体而言,我预计您示例中的“第二个#load”将打开例如 FSI_000N+1 版本的命名空间,而先前的代码则在 FSI_000N 中。这也许解释了为什么显式的 open 交互可以解决问题;您需要将现有的未被遮蔽的 FSI_000N 东西提升到顶层,然后再尝试(隐含地)稍后引用它。


3
没错,我的问题只是我实际代码的一个简化版本。最终,我通过在每个 #load 之间重新打开命名空间来使代码正常运行。 - Benjol

8

我对此也比较新,但是当我在fsx文件中进行测试时,以下方法对我有用:

#if INTERACTIVE
#r @"C:\Program Files\FSharpPowerPack-2.0.0.0\bin\FParsec.dll"
#r @"C:\Program Files\FSharpPowerPack-2.0.0.0\bin\FParsecCS.dll"
#endif

open FParsec.Primitives  
open FParsec.CharParsers

紧接着是我使用这些库的代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接