1. 無料アクセス解析
PGKiss実践的純粋関数プログラミング言語(CleanとHaskell)入門 - echo を作る

echoプログラムの全体像

ご存知のとおり、echoコマンドは引数で与えられた文字列を出力するコマンドだ。これをHaskellで書くとこうなる。

Main.hs

Haskellの場合、プログラムの実行はMainモジュールのmain関数から始まる。 入出力を行うためにはIOモナドという仕組みを使う。モナドについてはそのうち説明するとして、今は入出力をするには、do記法(4~6行目)を使う。上記のコードでは、argsをgetArgs関数呼び出し(INPUT)の結果と定義し、そのargsを引数にjoin関数を呼び出し、その結果をputStrLnで出力する(OUTPUT)という処理が行っている。

where以下では、main関数内でローカルに使える関数joinを定義している。以上がこのプログラムのアウトラインだ。

Cleanで書いたechoプログラムは下記のとおりだ。

echo.icl

Cleanの場合、プログラムの実行はいずれかのモジュールのStart関数から始まる。 Start関数は、外界とのインターフェースのために引数worldを受け取る。Start関数の仕事は、このworldとコマンドライン引数を関数mainに渡すところまでだ。残りの仕事は関数mainに任せることにする。Start関数のwhere以降では、コマンドライン引数を取得している。getCommandLineは、モジュールArgEnvで定義されている関数で、コマンド名と引数を配列で返す。これをリストに変換したものをargv、その先頭のコマンド名を取り除いたものをargsと定義している。

main関数では、実際に引数を出力している。入出力を行う処理は#で始まる行(16~18行目)で行っている。標準入出力のファイルハンドルをworldから取り出し、join関数の結果を出力し、ファイルをクローズしている。main関数のwhere以下では、join関数を定義している。

関数の定義

純粋関数プログラミング言語では、その名のとおり関数がプログラムの主役となる。関数を作るには、関数の型定義(Main.hsの8行目やecho.iclの21行目)と、関数自体の定義(Main.hsの9~11行目やecho.iclの22~24行目)をする。関数の型定義は省略できることも多い。Main.hsのmain関数の型定義は省略している。

関数の型定義では、「<関数名> ::」の後に、引数の型を並べ、最後に関数の戻り値の型を書く。上記のjoin関数では、第一引数の型がStringのリスト、第二引数の型がString、関数の戻り値の型がStringとなる。Cleanでは、引数の型を区切る「->」を省略できる。引数の型を区切る記号と、引数の型と戻り値の型を区切る記号が同じなのに違和感を感じるかもしれない。しかし、関数の引数の部分適用(カリー化)が可能なHaskellやCleanでは、むしろ自然だ。例えば、上記のjoin関数にStringのリスト型の引数を適用すると、結果として「String型の引数を一つ受け取りString型の値を返す関数」が得られる。

関数の(型ではなく振る舞いの)定義は、「=」の左側に、関数名と引数のパターンを書き、右側に、実引数が引数のパターンとマッチした際に実行する式を書く。上記のjoin関数は、第一引数が空リストのパターン([])、要素が一つだけのパターン([x])、要素がそれ以上のパターン([x:xs])に場合分けされて定義されている。多くの言語が、このような場合分けを関数の内部でif分などを使って記述するのと比べると、特徴的である。 join関数は第一引数のリストを、第二引数sepで区切って連結し、一つの文字列にする関数だ。これとほぼ同等なJavaによる実装は「何かで区切るする表現、splitter」を参照。

型の表記

CleanやHaskellは強く型付けされた(strongly typed)言語だ。正しいプログラムを作るには(プログラムの誤りを型エラーで検出するには)、型についてよく理解する必要がある。今回は、もっとも基本的な決まりに触れる。まず型名は大文字で始まる(Ex. String,Int,Worldなど)。また、「[]」はリストを表す。「[String]」はString型の要素を持つリスト型を表す。

演算子の定義

CleanやHaskellは、プログラマが自分で演算子を定義できる。C++では、演算子のオーバーロードができるだけだったが、HaskellやCleanでは、全く新たしい演算子を定義することもできる。これを表現力が高いと評価するか、プログラムの可読性、保守性を下げる要因とみなすかは、判断の分かれるところである。個人的には、一部のハッカーが利用する言語であれば演算子の定義ができてもよいが、JavaやC#のように大勢の一般的なプログラマが使う言語を目指すのであれば、演算子の定義やオーバーロードはないほうがよいと思う。上記のプログラムの「++」や「+++」は文字列を連結する演算子である。

演算子も、被演算子を引数に取る関数として扱われる。

inserted by FC2 system