是否可以跨文件拆分F#模块?
根据我的书,但这本书可能已经过时了 (F#的基础)
答案 0 :(得分:11)
显然不是:
C:\temp\Tim>type 1.fs 2.fs
1.fs
#light
module Module
let sayHello1 = printfn "Hello, "
2.fs
#light
module Module
let sayHello2 = printfn "world!"
C:\temp\Tim>fsc 1.fs 2.fs
Microsoft F# Compiler, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.6.2, compiling for .NET Framework Version v2.0.50727
2.fs(2,1): error FS0191: An implementation of the file or module Module has already been given.
更新:F#4.0中的错误已更改,现在是:
错误FS0248:名为“模块”的两个模块出现在此程序集的两个部分中
其中Module
是程序集的完全限定名称,包括名称空间部分。
答案 1 :(得分:6)
类型扩展很酷,希望它们允许交叉文件,同时仍然是内在的。如果在同一文件中执行类型扩展,它将编译为一个类,并且扩展可以访问私有成员,依此类推。如果你在另一个文件中执行它,它只是一个“可选”扩展,如C#静态扩展方法。 (即使F#规格说的不同。)
如果仅在设计师的支持下,如果没有解决这个问题,我会感到惊讶。如果内部类型扩展可以在程序集中的任何位置,那就太漂亮了。另一个选项,可能不是你想要的,是创建一个类型和一个模块,调用模块相同的名称,然后将ModuleSuffix标志添加到它:
type Foo() =
static member Bar = 1
[<CompilationRepresentationAttribute(CompilationRepresentationFlags.ModuleSuffix)>]
module Foo =
let Baz = 2
printfn "%d %d" Foo.Bar Foo.Baz
这在F#库中使用,因此它们可以具有类型List或其他类型,以及模块中的大量帮助程序。
答案 2 :(得分:4)
像Kurt所说,你可以为类型添加扩展方法,因此
// File1.fs
namespace Foo
type Mine() =
static member f1 () = ()
然后
// File2.fs
type Foo.Mine with
static member f2() = ()
Foo.Mine. // both f1 and f2 here
既然它是一个阶级而不是一个模块,你就失去了“开矿”的能力(但是能够超载);因此,根据您正在做的事情,这可能是也可能不是您可接受的选择。
答案 3 :(得分:3)
我有时会在几个地方拆分一个类型,比如:
module Foo
type Partial = Bar | BarInt of int
module Bar
type Foo.Partial with
member x.Extend = 5
let b = Foo.Bar.Extend
模块Foo和Bar位于不同的文件中。
答案 4 :(得分:3)
在我的一个项目中,目标是将操作Cp
和Rm
归档到单独的模块,但不要求用户为这两个任务打开两个名称空间。
open Xake.FileTasks
...
do! Cp "*/*.exe" "deploy/*.exe"
do! Rm "*/*.exe"
这是我的模块:
namespace Xake.FileTasks
[<AutoOpen>]
module RmImpl =
let Rm filemask target =
...
和另一个:
namespace Xake.FileTasks
[<AutoOpen>]
module CpImpl =
let Cp filemask target =
...