Haskell 入門


Haskell の関数

関数と引数

Haskell の関数を使うには、関数 引数1 引数2... のように関数名の後にスペースで区切って引数を並べていくだけだ。カッコも、コンマもいらない。

Prelude> div 6 2
3
Prelude> sum [1,2,3,4,5]
15
Prelude> sin (pi * 0.5)
1.0

関数の定義は関数名前と仮引数名前の後に = 記号を置き、その後に関数の定義を記述する。function などの関数定義のための特別な予約語はないので最初は戸惑うが、慣れると簡潔で気持ちがいい。

Prelude> double x = x * 2
Prelude> double 5
10

関数を複数行にわたって定義するときは、エディターで foo.hs のように拡張子に .hs をつけたファイルを作成し、それを ghci の :load コマンドで読み込む。また、ghci のコマンドラインからも :{ コマンドと :} コマンドの間に記述することができる。

Prelude> :{
Prelude| fact n =
Prelude| if n == 0 then 1
Prelude| else n * fact (n-1)
Prelude| :}
Prelude> fact 5
120

あるいは、ghic のコマンドライン1行に ; で区切って並べてもいい。

Prelude> a = 1; b = 2; func = a + b
Prelude> func
3

Haskell の関数はパターンで定義できるので、同名の関数を複数並べてもいい。その場合上に置かれた定義のパターンから順にパターンマッチが行われる。例えば階乗の関数の定義は次のように書ける。

Prelude> :{
Prelude| fact 0 = 1
Prelude| fact n = n * fact (n-1)
Prelude| :}
Prelude> fact 5
120

上のプログラムでは fact の引数が 0 より大きいときは、n * fact (n-1) が返され、0 のときは 1 が返される。したがって、

fact 3 = 3 * fact 2 = 3 * 2 * fact 1 = 3 * 2 * 1 * fact 0 = 3 * 2 * 1 * 1 = 6

のように fact 3 が展開されていって最後に階乗が計算される。Haskell の関数の実行は概ね上のような式の展開で行われるとイメージするとその動作が理解しやすくなる。

また、引数を括弧 () で囲むと引数がリストの場合のパターンマッチを使うことができる。

Prelude> mysum [] = 0; mysum (x:xs) = x + mysum xs
Prelude> mysum [1,2,3]
6

Haskell ではこのように関数の定義の仕方にいろいろな方法がある。また、パターンマッチで定義できるので if then else などの制御構造文が少なくコンパクトで読みやすい定義ができる。

関数と演算子

演算子は普通の計算のように、引数の間に置く、カッコも使える。

Prelude> (1 + 2) * 3
9
Prelude> "hello, " ++ "world"
"hello, world"

また、‘ (バッククォート)で囲むと演算子のように使える関数もある。この機能で関数名を関数として使ったり、演算子として使ったりすることができる。

Prelude> 6 `div` 2
3

逆に + のような演算子も()で囲むと関数名のように使える。演算子も関数のように扱うことができる。

Prelude> (+) 1 2
3

関数と演算子の優先順位について言うと、関数のほうが演算子より、優先順位が上だ。

Prelude> length [1,2] + length [3,4,5]
5

モジュールに定義されている関数の使い方

関数の中には、モジュールを読み込まないと使えないものがある。たとえば、sort は Prelude を立ち上げてすぐには使えないが、

Prelude> sort [2,1,3]

<interactive>:26:1: error:
    • Variable not in scope: sort :: [Integer] -> t
 &bnsp;  • Perhaps you meant ‘sqrt’ (imported from Prelude)

:m Data.List モジュールを読み込むと使えるようになる。

Prelude> Prelude> :m Data.List
Prelude Data.List> sort [2,1,8,7]
[1,2,7,8]

関数を連結する

関数は $ 演算子でつないで使うことができる。

Prelude Data.List> reverse $ sort [2,1,8,7]
[8,7,2,1]

Huskell は説明はやたらと難しいが、使ってみると考えたことがそのままプログラムにできる感じで使いやすい。しばらく使ってその感触に慣れてから本を改めて読むと分かりやすくなる。自分で理解できた部分だけでいいからしばらく使ってみると、Haskell の楽しさが分かる。