次の方法で共有


モジュール

F# のコンテキストでは、 モジュール は F# プログラムの値、型、関数値などの F# コードのグループです。 モジュール内のコードをグループ化すると、関連するコードを一緒に保持し、プログラムでの名前の競合を回避できます。

構文

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

注釈

F# モジュールは、型、値、関数値、 do バインド内のコードなどの F# コード コンストラクトのグループです。 静的メンバーのみを持つ共通言語ランタイム (CLR) クラスとして実装されます。 モジュール宣言には、ファイル全体がモジュールに含まれているかどうかに応じて、最上位モジュール宣言とローカル モジュール宣言の 2 種類があります。 最上位レベルのモジュール宣言には、モジュール内のファイル全体が含まれます。 最上位レベルのモジュール宣言は、ファイル内の最初の宣言としてのみ使用できます。

最上位レベルのモジュール宣言の構文では、オプションの 修飾名前空間 は、モジュールを含む入れ子になった名前空間名のシーケンスです。 修飾された名前空間を以前に宣言する必要はありません。

最上位モジュールで宣言をインデントする必要はありません。 ローカル モジュール内のすべての宣言をインデントする必要があります。 ローカル モジュール宣言では、そのモジュール宣言の下でインデントされた宣言のみがモジュールの一部です。

コード ファイルが最上位レベルのモジュール宣言または名前空間宣言で始まらない場合、ローカル モジュールを含むファイルの内容全体が、ファイルと同じ名前を持つ暗黙的に作成された最上位モジュールの一部になり、拡張子は付けず、最初の文字は大文字に変換されます。 たとえば、次のファイルを考えてみましょう。

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

このファイルは、次のように書き込まれたかのようにコンパイルされます。

module Program
let x = 40

ファイルに複数のモジュールがある場合は、各モジュールに対してローカル モジュール宣言を使用する必要があります。 外側の名前空間が宣言されている場合、これらのモジュールは外側の名前空間の一部です。 外側の名前空間が宣言されていない場合、モジュールは暗黙的に作成された最上位モジュールの一部になります。 次のコード例は、複数のモジュールを含むコード ファイルを示しています。 コンパイラは、 Multiplemodulesという名前の最上位モジュールを暗黙的に作成し、その最上位モジュールに MyModule1MyModule2 が入れ子になります。

// 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 回のコンパイルで複数のファイルがある場合、またはライブラリをビルドする場合は、ファイルの先頭に名前空間宣言またはモジュール宣言を含める必要があります。 F# コンパイラは、プロジェクトまたはコンパイル コマンド ラインにファイルが 1 つだけ存在し、アプリケーションを作成している場合にのみ、モジュール名を暗黙的に決定します。

アクセシビリティ修飾子には、publicprivateinternalのいずれかを指定できます。 詳細については、「 アクセス制御」を参照してください。 既定値はパブリックです。

モジュールでのコードの参照

別のモジュールから関数、型、値を参照する場合は、修飾名を使用するか、モジュールを開く必要があります。 修飾名を使用する場合は、必要なプログラム要素の名前空間、モジュール、および識別子を指定する必要があります。 修飾パスの各部分は、次のようにドット (.) で区切ります。

Namespace1.Namespace2.ModuleName.Identifier

モジュールまたは 1 つ以上の名前空間を開いて、コードを簡略化できます。 名前空間とモジュールを開く方法の詳細については、「 インポート宣言: open キーワード」を参照してください。

次のコード例は、ファイルの最後までのすべてのコードを含む最上位モジュールを示しています。

module Arithmetic

let add x y =
    x + y

let sub x y =
    x - y

同じプロジェクト内の別のファイルからこのコードを使用するには、次の例に示すように、修飾名を使用するか、関数を使用する前にモジュールを開きます。

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

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

モジュールは入れ子にすることができます。 内部モジュールは、新しいモジュールではなく内部モジュールであることを示すために、外側のモジュール宣言までインデントする必要があります。 たとえば、次の 2 つの例を比較します。 モジュール Z は、次のコードの内部モジュールです。

module Y =
    let x = 1

    module Z =
        let z = 5

ただし、モジュール Z は、次のコードで Y モジュールへの兄弟です。

module Y =
    let x = 1

module Z =
    let z = 5

モジュール Z は、モジュール Yの他の宣言までインデントされないため、次のコードの兄弟モジュールでもあります。

module Y =
        let x = 1

    module Z =
        let z = 5

最後に、外側のモジュールに宣言がなく、その直後に別のモジュール宣言が続く場合、新しいモジュール宣言は内部モジュールであると見なされますが、2 番目のモジュール定義が最初のモジュール定義よりもインデントされていない場合、コンパイラから警告が表示されます。

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

警告を排除するには、内部モジュールをインデントします。

module Y =
    module Z =
        let z = 5

ファイル内のすべてのコードを 1 つの外部モジュールに含め、内部モジュールが必要な場合、外側のモジュールは等号を必要とせず、外側のモジュールで行く内部モジュール宣言を含む宣言はインデントする必要はありません。 内部モジュール宣言内の宣言はインデントする必要があります。 次のコードは、このケースを示しています。

// 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

再帰モジュール

F# 4.1 では、含まれているすべてのコードを相互に再帰的にするモジュールの概念が導入されています。 これは、 module recを介して行われます。 module recを使用すると、型とモジュールの間で相互参照コードを記述できないといういくつかの問題を軽減できます。 この例を次に示します。

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 Orientation = orientation with get, set
        member val Sides: PeelState list = [ Unpeeled; Unpeeled; Unpeeled; Unpeeled ] with get, set

        member self.IsPeeled =
            self.Sides |> List.forall ((=) Peeled)

        member self.Peel() =
            BananaHelpers.peel self
            |> fun peeledSides -> self.Sides <- peeledSides

        member self.SqueezeJuiceOut() =
            raise (DontSqueezeTheBananaException self)

    module BananaHelpers =
        let peel (banana: 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)

            banana |> flip |> peelSides

例外 DontSqueezeTheBananaException とクラス Banana 両方が相互に参照されることに注意してください。 さらに、モジュール BananaHelpers とクラス Banana も相互に参照します。 RecursiveModule モジュールから rec キーワードを削除した場合、F# ではこれを表現できません。

この機能は、F# 4.1 の 名前空間 でも可能です。

こちらも参照ください