HaskellとSCons

This entry was posted by on Saturday, 5 June, 2010

またぞろHaskellのIOの話が一部で盛り上がっているようです。はじめに結論を述べておくと、けっきょくのところ、これは「どう理解したらいいか」(どういう脳内モデルを構築するか)という話であって、正解も何もありません。プログラムを書けるのであれば、おそらくその理解は正しいのです。

それでも何かを書こうと思ったのは、こういう比喩をあまり見かけないな、と思ったからです。

HaskellにおけるIOは非常に謎めいています。たとえば、putStrという関数があります。型はString -> IO ()で、引数として文字列を与えるとそれを出力(画面に表示)します……本当でしょうか。いいえ、それがちょっとちがうんですよね、という話です。

IO ()というのは、「IO動作」という「値」です。Haskellという言語のなかで、この値は何もしません。putStrは文字列を受け取り、IO ()という値を返す関数です。IO ()自体は特にどうということはない値です。しかし、Haskellの処理系は、このプログラムを実行するときにこのIO ()に遭遇すると、何らかの処理を行ないます。この場合は「画面に文字列を出力する」という処理が行われます。

なんだかまどろっこしく言い換えただけに思えるかもしれません。

では、ぜんぜん違う例で説明しましょう。SConsというソフトウェアです。SConsはPythonで書かれたビルドシステム(makeみたいなもの)です。SConsではPythonで書かれたビルドプログラム(SConstruct)を読み込み、ビルドを遂行します。

たとえば、hello.cというファイルをコンパイルするプログラムは次のように書きます。

Program('hello.c')

プログラムではなくオブジェクトファイルを作るならこうです。

Object('hello.c')

一見すると、Programという関数は「ファイルをコンパイルしてプログラムを作成する」という関数に見えるかもしれません。ですが、そうではないんですね。SConsではProgramなどは「ファイルをコンパイルしてプログラムを作成する」というビルドアクションオブジェクトを作成し、それを返します。SConsはSConstructを読み込んで実行し、それによって出来上がったビルドアクションオブジェクトを認識して、それからあらためてビルドアクションを実行するという二段構えになっています。

ですから、たとえば

print "Calling Program('hello.c')"
Program('hello.c')
print "Calling Program('goodbye.c')"
Program('goodbye.c')
print "Finished calling Program()"

こんなふうになっていれば、まずprintの中身が3行分表示され、それからビルドが実行されるようになります。

SConstructファイルはPythonで書きますが、ここで読んだ端から実際にビルドが実行されていくというのはあまりいい設計ではありません。特定のターゲットだけビルドしたい場合やクリーンビルドしたい場合、並列ビルドに対応させたい場合などのことを考えると、実際のビルドの実行はSConsの側で行うこととし、SConstructの方ではSConsが認識出来るビルドアクションオブジェクトをせっせと作成するに留めるというわけです。

HaskellのIOも似たような仕組みになっています。putStrそれ自体は、何も実行しません。引数となる文字列をもとに、「その文字列を出力する」というIOアクションオブジェクトを返します。SConsでProgram(‘hello.c’)と書いたところで、その時点では単にビルドアクションオブジェクトが返されるだけなのとよく似ています。ただし、SConsが最終的にビルドアクションを実行してビルドを遂行するのと同じように、Haskellの処理系もmainという変数に束縛されているIOアクションオブジェクトを「実行」します。しかし、「実行」するかどうかということはHaskellのプログラムにおいてはどうでもいいことです。Haskellのプログラマにできるのは、「mainとはこういうアクションである」という定義をすることだけです。

これはたとえなので、ちょっと簡略化が入っています。細かい違いを言い出せばきりがない。ですが「Haskellにおいてはアクションというのは第一級の値である」「最終的にmainに束縛されているアクションが実行される」というのはおそらく正しいのではないかと思います。

Comments are closed.