モジュール
このページでは,Haskell のモジュールシステムについて説明します.
1. モジュール
モジュール(module)とは,Haskell において関数や型をパッケージ化する役割を持つ概念です. 他の言語においてパッケージ,ストラクチャ,名前空間などと呼ばれている概念と同様です.
2. 標準モジュール
標準で定義されているモジュールには,次のようなものがあります. Haskell 98 と Haskell 2010 でモジュール名が変わっているので,注意が必要です.
| Haskell 98 | Haskell 2010 | 説明 |
|---|---|---|
| Prelude | Prelude | 基本的な関数や型 |
| Ratio | Data.Ratio | 有理数 |
| Complex | Data.Complex | 複素数 |
| Numeric | Numeric | 数値 |
| Ix | Data.Ix | インデックス |
| Array | Data.Array | 配列 |
| List | Data.List | リスト |
| Maybe | Data.Maybe | Maybe |
| Char | Data.Char | 文字 |
| Monad | Control.Monad | モナド |
| IO | System.IO | 入出力 |
| Directory | System.Directory | ディレクトリ |
| System | System.Environment | 環境 |
| Time | System.Time | 時間 |
| Locale | System.Locale | ロケール |
| CPUTime | System.CPUTime | CPU 時間 |
| Random | System.Random | 乱数 |
Prelude モジュールは,最も基本的な関数や型などが定義されたモジュールです.
モジュールをインポートする宣言を何も書かなくても,Prelude モジュールは暗黙のうちにインポートされます.
3. モジュールの利用
モジュール Data.List に定義されている関数 sort を利用するには,次のように書きます.
import Data.List
main = do print $ sort [2, 1, 3] -- 出力: [1, 2, 3]
print $ Data.List.sort [2, 1, 3] -- 出力: [1, 2, 3]
キーワード import で始まる宣言はインポート宣言と呼ばれます.
インポートするモジュールが複数ある場合,宣言はモジュールごとに書く必要があります.
モジュール Data.List からインポートされた sort には,sort または Data.List.sort と書くことでアクセスできます.
なお,Data.List.sort を Data . List . sort のように書くことはできません.
他に,インポート宣言は次のような書き方ができます.
| 記述 | 参照可能な名前 | 説明 |
|---|---|---|
| import M | x, y, M.x, M.y | すべてのエンティティをインポート |
| import M(x) | x, M.x | エンティティ x のみインポート |
| import M hiding (x) | y, M.y | エンティティ x 以外をインポート |
| import qualified M | M.x, M.y | モジュール名による修飾を必須化する |
| import M as N | x, y, N.x, N.y | モジュール名 M を N と置き換える |
例えば,Prelude モジュールで提供されている関数等の一部をインポートしたくない場合は,次のようにインポート宣言を書きます.
import Prelude hiding (take, length) -- Prelude の take, length を隠蔽
4. モジュールの作成
次の Geometry.hs は自作のモジュール Geometry を定義したものです.
Main.hs ではモジュール Geometry をインポートしています.
-- ファイル: Geometry.hs
module Geometry where
data Shape = Tri { base, height:: Double }
| Rect { width, height :: Double }
area :: Shape -> Double
area (Tri x y) = x * y / 2
area (Rect x y) = x * y
-- ファイル: Main.hs
import Geometry
main = do print $ width (Rect 3 4) -- 出力: 3.0
print $ height (Rect 3 4) -- 出力: 4.0
print $ area (Tri 3 4) -- 出力: 6.0
print $ area (Rect 3 4) -- 出力: 12.0
今回の Geometry.hs のように,モジュール定義はモジュール名と同名のファイルに保存する必要があります.
また,モジュール名は英字の大文字で始める必要があります.
5. エクスポートリスト
モジュール定義の冒頭を次のように書くことで,エクスポートするエンティティを選択できます.
module Geometry(Shape(Tri, Rect), area) where
モジュール名直後の (Shape(Tri, Rect), area) はエクスポートリストと呼ばれ,エクスポートするエンティティをここに列挙します.
エクスポートリストを省略した場合は,すべてのエンティティがエクスポートされます.
| 記述 | エクスポートの対象 |
|---|---|
| module Geometry where | すべてのエンティティ |
| module Geometry(Shape) where | 型構成子 Shape |
| module Geometry(area) where | 関数 area |
| module Geometry(Shape, area) where | 型構成子 Shape,関数 area |
型構成子,型クラスは,それに属するデータ構成子,フィールド,メンバ関数のエクスポートの有無も含めて記述します.
| 記述 | エクスポートの対象 |
|---|---|
| Shape | 型構成子 Shape |
| Shape(Tri, Rect) | 型構成子 Shape, データ構成子 Tri, Rect |
| Shape(Tri, base, height) | 型構成子 Shape, データ構成子 Tri, フィールド base, height |
| Shape(..) | 型構成子 Shape とそのデータ構成子,フィールドすべて |
また,次のように書くと,モジュール Numeric からインポートした内容を,モジュール Geometry で一緒にエクスポートできます.
module Geometry(module Geometry, module Numeric) where
import Numeric
6. 階層化されたモジュール
標準モジュールの Data.List, System.IO のように,モジュールに階層を持たせることができます.
自作のモジュール Geometry を階層に入れて Data.Geometry にするには,いままで Geometry と記述していた箇所をすべて Data.Geometry に書き直します.
さらに,ファイル Geometry.hs をディレクトリ Data に移動します.
module Data.Geometry where
-- 後略
import Data.Geometry
main = print $ area (Rect 3 4) -- 出力: 12.0
7. Main モジュール
モジュール名の記述がないファイルは,Main モジュールの記述として扱われます.
例として,次のような .hs ファイルが表すプログラムを考えます.
main = prtStrLn "hello, world"
このプログラムは,次のように記述される Main モジュールの頭部を省略したものと見なされます.
module Main(main) where
main = prtStrLn "hello, world"