人気ブログランキング | 話題のタグを見る

Yet Another Haskell Tutorial 8

6 Modules

Haskell プログラムのサブコンポーネントはモジュールだ。モジュールはそのモジュールと同じ名前のファイルに作成する。ただし、ファイルには、.hs 拡張子を付けなければならない。モジュールの目的はプログラムを部品化し再利用可能にすることだ。

6.1 Exports

モジュールの目的のひとつは、内部の型名や変数名や関数名を隠蔽することだ。Haskell のモジュールでは module 宣言の時に export list を作ることで外部に公開する関数や、データ構造を指定できる。export list は module 宣言のモジュール名と where キーワードの間で括弧に入れて提示する。

module Cards ( Card (),
               Deck (),
               newDeck,
               shuffle,
               deal
             )
    where

Card、Deck がタイプコンストラクタで、newDeck、shuffle、deal が関数だ。Card () の () は Card 型のデータコンストラクタを公開しないことを示している。Card のデータコンストラクタは実際は次のようになっている。

data Card = Card Suit Face
data Suit = Hearts
          | Spades
          | Diamonds
          | Clubs
data Face = Jack
          | Queen
          | King
          | Ace
          | Number Int

Card のデータコンストラクタも公開したい場合は、Card () の括弧の中にデータコンストラクタを記述する。上のデータ構造の場合、次のようなる。

module Cards ( Card(Card),
               Suit (Hearts, Spades, Diamonds, Clubs),
               Face (Jack, Queen, King, Ace, Number),
               ...
             )
    where

全てのデータコンストラクタを公開したい場合は上の記述は次のように簡略化できる。

mdule Cards ( Card(..),
              Suit(..),
              Face(..),
              ...
            )
    where

6.2 Imports

自作のプログラムからモジュールを利用したいときは import 宣言をする。次の例では Poker モジュールは Cards モジュールをインポートしている。

module Poker
    where

import Cards

Porker モジュールの関数と Cards モジュールの関数の名前が衝突する場合は、次のように qualified import を行う。

import qualified Cards

そうすると、Cards モジュールの newDeck 関数は Cards.newDeck としないと使えなくなるので、名前の衝突を回避できる。

名前の衝突を回避するためのもう一つの方法は、import 宣言の時に特定の関数だけをインポートすることだ。

import Cards (newDeck)

あるいは、hiding キーワードを使って特定の関数を隠す。

import Cards hiding (deal)

qualified import は as キーワードで別名を使うことができる。

import qualified Cards as C

これらのインポートのオプションは組み合わせることができる。例えば qualified/as import に import list を付け加えることができる。

6.3 Hierarchical Imports

モジュールの数が増えてくると、モジュールのファイルを階層性のファイルシステムにして保存する必要が出てくる。Haskell ではこのようなモジュールツリーにあわせて Import できるようになっている。例えば、Cards.hs ファイルの場所が haskell/Cards/Cards.hs にあったとすると、GHC に -i オプションで haskell ディレクトリの場所を教えておけば、Cards.hs モジュールは次のように Cards.Cards と名付けることができる。

module Cards.Cards
    where

このモジュールをインポートするには、次のようにする。

import Cards.Cards

関数の名前の衝突を避けるためには、qualified import を使う。

import qualified Cards.Cards

しかし、これでは例えば newDeck という関数を使うのに Cards.Cards.newDeck としなければならないので美しくない。Qualified import の as キーワードを使って次のように Cards.Cards モジュールに別名をつけるのが普通だ。

import qualified Cards.Cards as Cards

これなら、newDeck は Cards.newDeck で使える。

6.4 Literate Versus Non-Literate

一般にはプログラムのコードの補助的な役割としてコメントを記入する。そのときは、コメントであることを明示するため特別な記号 {- ... -} などを使う。

Literate program では逆にコメントの中に、特別な記号でコードを埋め込む。(管理人注:literate program は文芸的プログラムと訳されているが、文芸的というよりは、可読性の高いとか、著述的ななどと訳す方がふさわしい。要するに普通の文章として読めるプログラムということだ。)

Haskell では、'>' の後にコードを埋め込む Bird-scripts と LaTex のマークアップの中に埋め込むスタイルがある。(管理人注: 詳しい説明は YAHT の本文にあるので以下は例示のみにとどめる。)

6.4.1 Bird-scripts

This is a simple (literate!) Hello World program.
> module Main
>     where
All our main function does is print a string:
> main = putStrLn "Hello World"

6.4.2 LaTex-scripts

This is another simple (literate!) Hello World program.
\begin{code}
module Main
    where
\end{code}
All our main function does is print a string:
\begin{code}
main = putStrLn "Hello World"
\end{code}

Yet Another Haskell Tutorial 9 へ続く ...
by tnomura9 | 2013-02-04 18:49 | Haskell | Comments(0)
<< Yet Another Has... Peeping Life 傑作集 >>