モジュール

モジュールとは、定義の集合に名前を付ける機能のことです。 関連した定義だけをまとめることによって プログラムの独立性を高めることが出来ます。 F#のモジュールシステムはOCaml譲りですが  ・F#用の構文が推奨されている  ・Functorなどの一部の機能は実装されていない  ・OCamlとは違い、モジュール名は大文字/小文字どちらでもOK といった違いがあるようです。(他にもありそうです) モジュールの定義にはF#版/OCaml版の2種類の構文が使えます。
F#版のモジュールの構文
モジュール定義:= begin [モジュール要素]* end モジュール要素:= | let式 | type定義 | 例外定義 | モジュール定義 | モジュールの省略名の定義 | import宣言 モジュールの省略名の定義:= module 省略名 = モジュール名
OCaml互換のモジュールの構文
モジュール定義:= struct [モジュール要素]* end (他は共通)
なお、#lightの場合begin,endは省略出来ます それでは、実際にモジュールを作ってみます
モジュールの作成
//最小のモジュール。モジュール名は小文字でもOK
module a = begin end;;

//letを用いて値を定義
module b = begin let a = 2 end;;

//OCamlスタイル
module c = struct let a = 3 end;;

//モジュールのアクセスにはドットを用いる
printfn "%d" (b.a);;
printfn "%d" (c.a);;
この例では3つのモジュールa,b,cを定義しています。 モジュールの中で定義されているものへアクセスするには この例のようにドットを用います。
他の形式のモジュール定義
//型の定義。大文字のモジュール名ももちろんOK
module D = begin type A = int end;;

//例外の定義
module E = begin exception EX end;;

//モジュールの省略名の定義
module M = Microsoft.FSharp.Collections.Seq;;
//これは不可。System.Windows.Formsはモジュールではなく名前空間(後に説明)
//module WF = System.Windows.Forms

//省略名の利用
M.map ((+)1) [1..10] |> print_any;;</code>
続いて、型、例外、省略名を定義してみた例です。 これらは、一つのモジュールに複合して入れることが出来ます。
モジュールの中に色々と定義
module Mix = begin
    let a = 10
    type T = int
    exception E
end
また、モジュールは入れ子に出来ます
モジュールの入れ子
module A = begin
    module B = begin
        let b = 5
    end
end;;
printfn "%d" (A.B.b);;
モジュールに対して毎回ドットを付けてアクセスするのが 面倒な場合は、モジュールをopenすることができます。 (定義で言えば、import宣言の所)
モジュールのopen
module A = begin
    let a = 6
end;;
open A;;
printfn "%d" a;;
この例ではAというモジュールを定義していますが open Aとしたことによって ドットを付けなくても 直接Aの中のaにアクセス出来てしまうわけです。 これは、直接モジュールの中で使用できます。 この場合、モジュールの外側にはopenの影響はありません。
モジュール内でopen
module A = begin
    open List
    let a = map ((+)1) [1..10]
end;;

A.a |> print_any;;
//error:The value or constructor 'map' is not defined
//map ((+)1) [1..10];;
色々バッティングしそうな名前の関数が定義されているため、 通常、Listモジュールはopenしません しかし、モジュールA内部でListをオープンしても モジュール外には影響はないため このような使い方が出来ます。 さらに、モジュールを自動的にオープンしてくれる AutoOpen属性(Microsoft.FSharp.Core.AutoOpenAttribute) を付けることが出来ます。 モジュールを入れ子にしてAutoOpenの動作を 確認したのが次のプログラムです。 A2のパターンは自分にとっては少し予想外の動作でした。
AutoOpen属性
#light "off"

module A1 = begin
    let a1 = 1
    module B1 = begin let b1 = 11 end
end;;

module A2 = begin
    let a2 = 2
    [<AutoOpen>]
    module B2 = begin let b2 = 22 end
end;;

[<AutoOpen>]
module A3 = begin
    let a3 = 3
    module B3 = begin let b3  = 33 end
end;;

[<AutoOpen>]
module A4 = begin
    let a4 = 4
    [<AutoOpen>]
    module B4 = begin let b4 = 44 end
end;;
printfn "%d,%d" (A1.a1) (A1.B1.b1);;

printfn "%d,%d" (A2.a2) (A2.B2.b2);;
//printfn "%d,%d" (A2.a2) (A2.b2);;   //これは動作しないようです

printfn "%d,%d" a3 (B3.b3);;

printfn "%d,%d" a4 b4;;
AutoOpenしたモジュールは モジュール名の修飾なしにアクセスすることが 出来ることが確認できます。 参考:The F# 1.9.6 Draft 9.5 Module Definitions