モジュールModules

F # 言語のコンテキストでは、モジュールは f # プログラムの f # コード (値、型、関数値など) をグループ化したものです。In the context of the F# language, a module is a grouping of F# code, such as values, types, and function values, in an F# program. モジュールのコードをグループ化すると、関連するコードをまとめることができ、プログラム内で名前の競合を回避するのに役立ちますGrouping code in modules helps keep related code together and helps avoid name conflicts in your program.

構文Syntax

// Top-level module declaration.
module [accessibility-modifier] [qualified-namespace.]module-name
declarations
// Local module declaration.
module [accessibility-modifier] module-name =
    declarations

RemarksRemarks

F # モジュールは、型、値、関数の値、バインド内のdoコードなどの f # コードコンストラクターをグループ化したものです。An F# module is a grouping of F# code constructs such as types, values, function values, and code in do bindings. 静的メンバーのみを持つ共通言語ランタイム (CLR) クラスとして実装されます。It is implemented as a common language runtime (CLR) class that has only static members. モジュール宣言には、ファイル全体がモジュールに含まれるかどうかに応じて、最上位のモジュール宣言とローカルモジュール宣言の2種類があります。There are two types of module declarations, depending on whether the whole file is included in the module: a top-level module declaration and a local module declaration. 最上位レベルのモジュール宣言には、モジュール内のファイル全体が含まれます。A top-level module declaration includes the whole file in the module. 最上位レベルのモジュール宣言は、ファイル内の最初の宣言としてのみ使用できます。A top-level module declaration can appear only as the first declaration in a file.

最上位のモジュール宣言の構文では、省略可能な修飾名前空間は、モジュールを含む入れ子になった名前空間の名前のシーケンスです。In the syntax for the top-level module declaration, the optional qualified-namespace is the sequence of nested namespace names that contains the module. 修飾された名前空間は、事前に宣言されている必要はありません。The qualified namespace does not have to be previously declared.

最上位のモジュールで宣言にインデントを付ける必要はありません。You do not have to indent declarations in a top-level module. ローカルモジュール内のすべての宣言をインデントする必要があります。You do have to indent all declarations in local modules. ローカルモジュール宣言では、そのモジュール宣言の下でインデントされた宣言のみがモジュールの一部になります。In a local module declaration, only the declarations that are indented under that module declaration are part of the module.

最上位のモジュール宣言または名前空間宣言で開始されていないコードファイルの場合、ローカルモジュールを含むファイルの内容全体が、暗黙的に作成された最上位レベルのモジュールの一部になります。このモジュールは拡張子を付けずに、最初の文字を大文字に変換したものです。If a code file does not begin with a top-level module declaration or a namespace declaration, the whole contents of the file, including any local modules, becomes part of an implicitly created top-level module that has the same name as the file, without the extension, with the first letter converted to uppercase. たとえば、次のファイルについて考えてみます。For example, consider the following file.

// In the file program.fs.
let x = 40

このファイルは、次のように記述されているかのようにコンパイルされます。This file would be compiled as if it were written in this manner:

module Program
let x = 40

ファイルに複数のモジュールがある場合は、モジュールごとにローカルモジュール宣言を使用する必要があります。If you have multiple modules in a file, you must use a local module declaration for each module. 外側の名前空間が宣言されている場合、これらのモジュールは外側の名前空間の一部になります。If an enclosing namespace is declared, these modules are part of the enclosing namespace. 外側の名前空間が宣言されていない場合、これらのモジュールは、暗黙的に作成された最上位レベルのモジュールの一部になります。If an enclosing namespace is not declared, the modules become part of the implicitly created top-level module. 次のコード例は、複数のモジュールを含むコードファイルを示しています。The following code example shows a code file that contains multiple modules. コンパイラは、という名前MultiplemodulesMyModule1トップレベルモジュールを暗黙的にMyModule2作成し、その最上位モジュールに入れ子になっています。The compiler implicitly creates a top-level module named Multiplemodules, and MyModule1 and MyModule2 are nested in that top-level module.

// In the file multiplemodules.fs.
// MyModule1
module MyModule1 =
    // Indent all program elements within modules that are declared with an equal sign.
    let module1Value = 100

    let module1Function x =
        x + 10

// MyModule2
module MyModule2 =

    let module2Value = 121

    // Use a qualified name to access the function.
    // from MyModule1.
    let module2Function x =
        x * (MyModule1.module1Function module2Value)

1つのプロジェクトまたは1つのコンパイルに複数のファイルがある場合、またはライブラリをビルドする場合は、ファイルの先頭に名前空間宣言またはモジュール宣言を含める必要があります。If you have multiple files in a project or in a single compilation, or if you are building a library, you must include a namespace declaration or module declaration at the top of the file. F # コンパイラは、プロジェクトまたはコンパイルコマンドラインにファイルが1つしかない場合に、暗黙的にモジュール名を特定するだけで、アプリケーションを作成します。The F# compiler only determines a module name implicitly when there is only one file in a project or compilation command line, and you are creating an application.

アクセシビリティ修飾子publicprivate、、 internalのいずれかにすることができます。The accessibility-modifier can be one of the following: public, private, internal. 詳しくは、「アクセス制御」をご覧ください。For more information, see Access Control. 既定値はパブリックです。The default is public.

参照 (モジュールのコードを)Referencing Code in Modules

別のモジュールから関数、型、および値を参照する場合は、修飾名を使用するか、モジュールを開く必要があります。When you reference functions, types, and values from another module, you must either use a qualified name or open the module. 修飾名を使用する場合は、名前空間、モジュール、および必要なプログラム要素の識別子を指定する必要があります。If you use a qualified name, you must specify the namespaces, the module, and the identifier for the program element you want. 修飾されたパスの各部分は、次のようにドット (.) で区切ります。You separate each part of the qualified path with a dot (.), as follows.

Namespace1.Namespace2.ModuleName.Identifier

モジュールまたは1つ以上の名前空間を開いて、コードを簡略化できます。You can open the module or one or more of the namespaces to simplify the code. 名前空間とモジュールを開く方法の詳細については、「宣言のopenインポート: キーワード」を参照してください。For more information about opening namespaces and modules, see Import Declarations: The open Keyword.

次のコード例は、ファイルの末尾までのすべてのコードを含む最上位のモジュールを示しています。The following code example shows a top-level module that contains all the code up to the end of the file.

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

同じプロジェクト内の別のファイルからこのコードを使用するには、次の例に示すように、修飾名を使用するか、または関数を使用する前にモジュールを開きます。To use this code from another file in the same project, you either use qualified names or you open the module before you use the functions, as shown in the following examples.

// Fully qualify the function name.
let result1 = Arithmetic.add 5 9
// Open the module.
open Arithmetic
let result2 = add 5 9

入れ子になったモジュールNested Modules

モジュールは入れ子にすることができます。Modules can be nested. 内部モジュールは、新しいモジュールではなく内部モジュールであることを示すために、外部モジュール宣言と同じようにインデントする必要があります。Inner modules must be indented as far as outer module declarations to indicate that they are inner modules, not new modules. たとえば、次の2つの例を比較します。For example, compare the following two examples. モジュールZは、次のコードの内部モジュールです。Module Z is an inner module in the following code.

module Y =
    let x = 1

    module Z =
        let z = 5

ただし、 Zモジュールは次のコードYのモジュールの兄弟です。But module Z is a sibling to module Y in the following code.

module Y =
    let x = 1

module Z =
    let z = 5

モジュールZは、モジュールY内の他の宣言と同じようにインデントされないため、次のコードの兄弟モジュールでもあります。Module Z is also a sibling module in the following code, because it is not indented as far as other declarations in module Y.

module Y =
        let x = 1

    module Z =
        let z = 5

最後に、外側のモジュールに宣言がなく、その後に別のモジュール宣言が直後にある場合、新しいモジュールの宣言は内部モジュールと見なされますが、2番目のモジュール定義が最初のモジュールよりも先にインデントされていない場合は、コンパイラによって警告が表示されます。Finally, if the outer module has no declarations and is followed immediately by another module declaration, the new module declaration is assumed to be an inner module, but the compiler will warn you if the second module definition is not indented farther than the first.

// This code produces a warning, but treats Z as a inner module.
module Y =
module Z =
    let z = 5

警告を回避するには、内側のモジュールをインデントします。To eliminate the warning, indent the inner module.

module Y =
    module Z =
        let z = 5

ファイル内のすべてのコードを1つの外部モジュールに配置し、内部モジュールを使用する場合、外側のモジュールでは等号を必要とせず、外側のモジュールで使用される内部モジュール宣言を含む宣言をインデントする必要はありません。If you want all the code in a file to be in a single outer module and you want inner modules, the outer module does not require the equal sign, and the declarations, including any inner module declarations, that will go in the outer module do not have to be indented. 内部モジュール宣言内の宣言は、インデントする必要があります。Declarations inside the inner module declarations do have to be indented. 次のコードはこのケースを示しています。The following code shows this case.

// The top-level module declaration can be omitted if the file is named
// TopLevel.fs or topLevel.fs, and the file is the only file in an
// application.
module TopLevel

let topLevelX = 5

module Inner1 =
    let inner1X = 1
module Inner2 =
    let inner2X = 5

再帰的なモジュールRecursive modules

F # 4.1 では、含まれているすべてのコードを相互に再帰的に使用できるモジュールの概念が導入されています。F# 4.1 introduces the notion of modules which allow for all contained code to be mutually recursive. これは、をmodule rec使用して行います。This is done via module rec. を使用module recすると、型とモジュール間で相互参照コードを記述できないという問題を軽減できます。Use of module rec can alleviate some pains in not being able to write mutually referential code between types and modules. この例を次に示します。The following is an example of this:

module rec RecursiveModule =
    type Orientation = Up | Down
    type PeelState = Peeled | Unpeeled

    // This exception depends on the type below.
    exception DontSqueezeTheBananaException of Banana

    type Banana(orientation : Orientation) =
        member val IsPeeled = false with get, set
        member val Orientation = orientation with get, set
        member val Sides: PeelState list = [ Unpeeled; Unpeeled; Unpeeled; Unpeeled] with get, set

        member self.Peel() = BananaHelpers.peel self // Note the dependency on the BananaHelpers module.
        member self.SqueezeJuiceOut() = raise (DontSqueezeTheBananaException self) // This member depends on the exception above.

    module BananaHelpers =
        let peel (b: Banana) =
            let flip (banana: Banana) =
                match banana.Orientation with
                | Up ->
                    banana.Orientation <- Down
                    banana
                | Down -> banana

            let peelSides (banana: Banana) =
                banana.Sides
                |> List.map (function
                             | Unpeeled -> Peeled
                             | Peeled -> Peeled)

            match b.Orientation with
            | Up ->   b |> flip |> peelSides
            | Down -> b |> peelSides

例外DontSqueezeTheBananaExceptionとクラスBananaは両方とも参照していることに注意してください。Note that the exception DontSqueezeTheBananaException and the class Banana both refer to each other. さらに、モジュールBananaHelpersとクラスBananaも相互に参照します。Additionally, the module BananaHelpers and the class Banana also refer to each other. RecursiveModuleモジュールからrecキーワードを削除した場合、これを F # で表現することはできません。This would not be possible to express in F# if you removed the rec keyword from the RecursiveModule module.

この機能は、名前空間で F # 4.1 を使用して行うこともできます。This capability is also possible in Namespaces with F# 4.1.

関連項目See also