はじめの一歩

このページでは,Haskell プログラムの基本的な書き方について説明します.

1. Hello World

まずは Hello World プログラムから始めましょう. Haskell の Hello World プログラムは次のように書きます.

main = putStrLn "hello, world"

ソースコードの拡張子は .hs とするのが通例です. このソースコードを hello.hs のようなファイル名で保存し,コンパイル&実行してみましょう.

% ghc hello.hs
[1 of 1] Compiling Main             ( hello.hs, hello.o )
Linking hello ...
% ./hello
hello, world

C における main 関数と同様に,Haskell でも main という名前がプログラムのエントリポイントとなります. main には,プログラムが実行すべき I/O アクションを記述します.

Haskell で関数を利用するには, f(x, y) という形ではなく f x y という形で式を書きます. 今回のプログラムの putStrLn "hello, world" は,引数の文字列 "hello, world" に関数 putStrLn を適用するという処理を表します.

関数型プログラミングでは,関数を "呼び出す(call)" ではなく,関数を引数に "適用する (apply)" という言い方が好まれます.

putStrLn は文字列を改行とともに出力する関数です. 改行が不要であれば putStr を使います. また,文字列以外の式を文字列化して出力するために,次のように print 関数を使うこともできます(主にデバッグ用).

main = print 123

2. コメント

Haskell で使えるコメントには,-- から始まる行コメントと,{- から -} までのブロックコメントの 2 種類があります. ブロックコメントはネストすることができます.

-- ここは行コメント

main = putStrLn "hello, world"  -- ここも行コメント

{- ブロックコメントは
   {- ネストさせてもよい -}
-}

3. ブロック

ブロック(block)は複数の式をまとめて 1 つの式にする構文です. { 式1; …​; 式n } という形式で記述します. 例として,次のような do ブロックを使うことで,main に複数のアクションを記述することができます.

main = do { putStrLn "hello" ; putStrLn "world" ; putStrLn "goodbye" }

このプログラムの出力は次のようになります.

hello
world
goodbye

ブロック内の式をすべて同一の行に書く場合には,最初と最後の波括弧 {, } は省略できます.

main = do putStrLn "hello" ; putStrLn "world" ; putStrLn "goodbye"

ブロックは必ず do のようなキーワードと一緒に使います. ブロックを導入するキーワードとして,do のほかには where, let, of があります.

4. レイアウト

ブロック { …​ } は,レイアウト(layout)を利用して見やすく書き換えることができます. レイアウトは,インデントのレベルによってブロックの範囲を表す仕組みです. Python でも同じようなしくみがありますね.

例えば,先ほどのプログラムの do ブロックは,レイアウトを使うと次のように書けます.

main = do putStrLn "hello"
          putStrLn "world"
          putStrLn "goodbye"

複数の式のインデントを揃えることにより,それらの式が同じブロックに属することを示します. この例では,3 つの式 (putStrLn "…​") のインデントを揃えることで,これらの式が同じブロックに属することを示しています.

この規則を "レイアウト規則" とか "オフサイドルール" とか呼んだりもます.

インデントの基準は,キーワード do, where, let, of の後に現れる最初の式によって決められます. また,インデントの位置は必ずしもこれらのキーワードより右側である必要はありません. ですので,このプログラムは次のように書くこともできます.

main = do
    putStrLn "hello"
    putStrLn "world"
    putStrLn "goodbye"

ブロック内の一つの式を複数行に分けて書きたいときは,次のようにインデントを深くします.

main = do
    putStrLn
        "hello"
    putStrLn
        "world"
    putStrLn
        "goodbye"

5. 変数

変数の定義は次のように書きます. 変数の型は推論されるので,明示する必要はありません.

変数名 = 

変数を値に結びつけることを,変数の 束縛 (binding) といいます. 次の例では,変数 m は値 123 に,変数 n は値 456 にそれぞれ束縛されます.

m = 123   -- 変数 n を値 123 に束縛
n = 456   -- 変数 n を値 456 に束縛

main = do print m  -- 出力: 123
          print n  -- 出力: 456

変数の定義に関するもっと詳しい話は "式と宣言" のページで扱います.

6. 関数

次のプログラムは,2 数の和を計算する関数 add を定義したものです.

add x y = x + y

main = print (add 2 3)  -- 出力: 5

一般に,関数定義は次のように書きます.

関数名 引数1 ... 引数n = 

関数適用も同様に,引数を空白で区切って並べ,次のように書きます.

関数名 引数1 ... 引数n

関数に関するもっと詳しい話は "関数" のページで扱います.

7. 識別子

Haskell では,小文字で始まる 変数識別子(variable identifier)と大文字で始まる 構成子識別子(constructor identifier)という 2 種類の識別子を使い分けます.

使い分けの詳細は次の表の通りです. これらの識別子の使い分けは自然に覚えられるので,この表を暗記する必要はありません.

識別子の種類 用途 最初の文字

変数識別子

変数,関数,型変数

小文字 (a-z), アンダースコア (_)

foo, fooBar, x1, x', _x

構成子識別子

データ構成子,型構成子,型クラス,モジュール

大文字 (A-Z)

Foo, FooBar, Z1, X'

どちらも,2 文字目以降には英数字 (A-Z, a-z, 0-9),アンダースコア (_),シングルクォート (') が使えます. また,Unicode 文字を使った識別子も許されています.

予約語には次のようなものがあり,これらは識別子として使うことができません.

case  class   data     default  deriving  do      else
if    import  in       infix    infixl    infixr  instance
let   module  newtype  of       then      type    where    _

また,"演算子" と呼ばれるタイプの特殊な識別子を関数名などに使うこともできます. 詳細については "演算子" のページで説明します.

8. 多相型

Haskell では,一部分がパラメータ化された型である,多相型(polymorphic type)がよく使われます. Java や C# のジェネリクス(総称型)と同様の概念です.

例えば,次の例に示す fst という関数は,多相型をもつ関数の代表的な例です. fst はタプル(日本語だと "組")と呼ばれるデータ構造から最初の要素を取り出す関数であり,いろいろな要素型のタプルに対して使えます.

fst (123, 456)      -- 値: 123
fst ("abc", "def")  -- 値: "abc"
fst (123, "abc")    -- 値: 123

GHCi で fst の型を調べると,この関数の型はパラメータ化されていることがわかります.

Prelude> :t fst
fst :: (a, b) -> a

この ab は "型変数" あるいは "型パラメータ" とよばれ,何かひとつの具体型がここに入ることを表します. 同じ名前の型変数には,同じ具体型が入ります.

このチュートリアルでデータ型に a みたいな文字が入っていたら,それは型変数だと思ってください.