モジュール

1. モジュール

モジュール(module)とは,Haskell において関数や型をパッケージ化する役割を持つ概念です. 他の言語においてパッケージ,ストラクチャ,名前空間などと呼ばれている概念と同様です.

2. 標準モジュール

標準で定義されているモジュールには,次のようなものがあります. Haskell 98 と Haskell 2010 でモジュール名が変わっているので,注意が必要です.

Haskell 98Haskell 2010説明
PreludePrelude基本的な関数や型
RatioData.Ratio有理数
ComplexData.Complex複素数
NumericNumeric数値
IxData.Ixインデックス
ArrayData.Array配列
ListData.Listリスト
MaybeData.MaybeMaybe
CharData.Char文字
MonadControl.Monadモナド
IOSystem.IO入出力
DirectorySystem.Directoryディレクトリ
SystemSystem.Environment環境
TimeSystem.Time時間
LocaleSystem.Localeロケール
CPUTimeSystem.CPUTimeCPU 時間
RandomSystem.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.sortData . List . sort のように書くことはできません.

他に,インポート宣言は次のような書き方ができます.

記述参照可能な名前説明
import Mx, y, M.x, M.yすべてのエンティティをインポート
import M(x)x, M.xエンティティ x のみインポート
import M hiding (x)y, M.yエンティティ x 以外をインポート
import qualified MM.x, M.yモジュール名による修飾を必須化する
import M as Nx, 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"