top page > computer > haskell > web_lecture > for_programmer > adt_import.html
更新日:
文責: 重城良国

構文: 代数的データ型のインポート

はじめに

型Tree

ライブラリData.Treeに一般的な樹構造のコンテナが定義されている。

Data.Tree

% ghci
Prelude> :m Data.Tree
Prelude Data.Tree> :info Tree
data Tree a = Node {rootLabel :: a, subForest :: Forest a}
-- Defined in ‘Data.Tree’
instance [safe] Eq a => Eq (Tree a) -- Defined in ‘Data.Tree’
instance [safe] Monad Tree -- Defined in ‘Data.Tree’
instance [safe] Functor Tree -- Defined in ‘Data.Tree’
instance [safe] Read a => Read (Tree a) -- Defined in ‘Data.Tree’
instance [safe] Show a => Show (Tree a) -- Defined in ‘Data.Tree’
Prelude Data.Tree> :info Forest
type Forest a = [Tree a] -- Defined in `Data.Tree'

型Treeの定義は

data Tree a = Node { rootLabel :: a, subForest :: Forest a }
type Forest a = [Tree a]

となっている。ノードには必ずラベルがつく。子要素は2個以外にも0個以上の任意の個数持つことができる。子要素が0個の節が葉となる。わかりやすくするためにレコード構文を使わない定義にし型シノニムForestも展開すると

data Tree a = Node a [Tree a]

となる。

樹

この樹はTree型の値で表現すると

Node 'a' [Node 'b' [Node 'd' [], Node 'e' []], Node 'c' []]

となる。葉を子要素0の節として表現している。

暗黙のインポート

import Data.Tree

のようにするとこのモジュールが公開しているすべての名前が導入される。これだと使われている変数がどのモジュール由来なのかわからなくなる。コードを読むときの大きな障害だ。

import Asparagus
import Beetroot
import Carrot
.
.
.
import Zucchini

favorites :: [Parts]
favorites = [stem, leaf]

stemやleafの定義を読みたければモジュールAsparagusからZucchiniまでのファイルを検索する。

修飾名つきインポート

ひとつの解決策は修飾名をつけてインポートすることだ。

import qualified Asparagus as A
import qualified Beetroot as B
import qualified Carrot as C
.
.
.
import qualified Zucchini as Z

favorites :: [Parts]
favorites = [A.stem, C.leaf]

このようにすればstemがAsparagusで、leafがCarrotで定義されているのは自明だ。

インポートリストの明示

修飾名を使うのがわずらわしい場合はインポートリストを明示する。

import Asparagus (stem, asparagus)
import Beetroot (root, beetroot)
import Carrot (leaf, redmonster)
.
.
.
import Zucchini (zapallo, zucchini)

favorites :: [Parts]
favorites = [stem, leaf]

stemやleafが定義されているモジュールは明らかだ。

代数的データ型のインポート

adt_bad_import.hs

adt_good_import.hs

変数のインポートはそのまま書けば良い。代数的データ型についてはどうだろうか。値構築子Nodeが使いたいとする。

import Data.Tree (Node)

tree1 = Node 'a' []

のようにしたとする。

% ghci adt_bad_import.hs
GHCi, version 7.8.4: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main ( adt_bad_import.hs, interpreted )

adt_bad_import.hs:1:19:
In module ‘Data.Tree’:
‘Node’ is a data constructor of ‘Tree’
To import it use
‘import’ Data.Tree( Tree( Node ) )
or
‘import’ Data.Tree( Tree(..) )
Failed, modules loaded: none.
Prelude>

エラーだ。値構築子はそのままではインポートリストに書けない。型名のあとの括弧内に書く。

import Data.Tree (Tree(Node))

tree1 = Node 'a' []

% ghci adt_good_import.hs
*Main> tree1
Node {rootLabel = 'a', subForest = []}

型に含まれる名前をすべてインポート

型名に続けて(..)とすると型に含まれるすべての名前をインポートできる。すべての値構築子とフィールド名がインポートされる。

import Data.Tree (Tree(..))

tree1 = Node 'a' []

まとめ

モジュールのインポートで、公開されたすべての名前をインポートする方法がある。あまり良くない。修飾名をつけるかインポートリストを明示する。値構築子は型名のあとの括弧内に書く。型名のあとに(..)とするとその型の値構築子とフィールド名をすべてインポートできる。

「構文: レコード構文」へもどる 「構文: モジュールの作成」へ

正当なCSSです! HTML5 Powered with CSS3 / styling, and Semantics