将F#模块拆分为同一文件中的多个部分

时间:2018-06-21 01:49:28

标签: f#

我有以下工作的F#源文件

namespace Namspa1

[<AutoOpen>]
module M1 = 
    let [<Literal>] constant1 = "Hello, "

type Greeter(name) = 
    member x.Greet() = sprintf "%s%s" constant1 name

module M2 =
    let greet name = Greeter(name).Greet()

这有效,但是我要定义的功能是在定义了constant1的同一模块M1中打招呼。 换句话说,我只想使用一个文件即可获取

Namspa1.M1.constant1
Namspa1.Greeter
Namspa1.M1.greet //not Namspa1.M2.greet
  • constant1是一个值,因此必须在模块内部
  • Greater使用constant1,因此必须在文件的后面;我希望它在命名空间中,而不是在模块内部,因此它是非缩进的
  • 最后一个问候是一个函数,因此它必须在一个模块中,并且我想使用相同的模块M1。它也使用Greeter,因此必须位于类型定义之后。

如果我尝试将greet函数定义更改为

module M1 =
    let greet name = Greeter(name).Greet()

我收到M1的重复定义错误。

我该怎么做?

编辑

建议使用属性CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)修复重复定义错误,这是正确的,因此谢谢。

但是我的请求是关于扩展M1。我希望能够像在M1中定义函数一样使用M1.greet。 例如,如果我尝试在外部使用定义(例如另一个源文件),则可以使用M2.greet,因此我想使用M1.greet,这对于属性是不可能的

2 个答案:

答案 0 :(得分:3)

可以通过将CompilationRepresentation属性设置为CompilationRepresentationFlags.ModuleSuffix来实现。像这样扩展模块不是预期的用例,因此第二个模块定义需要移到单独的源文件中。

第一个文件:

namespace Namspa1

[<AutoOpen>]
module M1 = 
    let [<Literal>] constant1 = "Hello, "

type Greeter(name) = 
    member x.Greet() = sprintf "%s%s" constant1 name

第二个文件:

namespace Namspa1

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module M1 =
    let greet name = Greeter(name).Greet()

从技术上讲,它会生成一个名为M1Module的模块,这将影响从其他.NET语言的访问。

答案 1 :(得分:2)

使用recursive namespace可以实现您想要的目标。在声明名称空间时,请注意rec关键字。

namespace rec Namspa1

[<AutoOpen>]
module M1 =
    let [<Literal>] constant1 = "Hello, "
    let greet name = Greeter(name).Greet()

type Greeter(name) =
    member x.Greet() = sprintf "%s%s" constant1 name