モジュール
このページでは,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"