Writerモナドの使い道 計算の経過を得る

1から10まで足し算するコードを考えてみよう。関数型言語では高階関数を使ってすっきり表現できる。
ただ、このコードには欠点がある。最後の結果求めるには十分だが、足し算の経過を見たいときどうしてよいか分からない。

手続き型言語で書かれたコードだったら、一行追加するだけで良いかもしれない。
では関数型言語ではどうするのか?

方法1. IOモナドを使う

(+) の IOモナド対応版(addIO)を作り、foldl を foldM に変えれば、addIO内でputStrLnが使えるようになる。ただ、これだと純粋な関数ではなくなり、IOを引きずっている箇所でしか利用できない。

方法2. trace を使う

Haskell には純粋な関数内での計算をデバッグ出力する関数が用意されている。trace は 第一引数を標準出力に表示し、第二引数と同じものに評価される関数だ。場合によってはこれで十分だろう。ただ、経過の値を他の計算でも利用したいとき、標準出力に表示されてしまったものを利用することはできない。

方法3. Writerモナド を使う

そこでWriterモナド登場。WriterモナドはIOモナドと違い純粋関数内で実行でき、コードに下記のように手を加えることで、結果にいたるまでの過程の値を最後にリストとして得ることが出来る。

全部のせておく。

継続モナドの使い道 早期リターン

引数をチェックして、問題があれば Left に包んだエラーメッセージに、問題がなければ Right に包んだ計算結果に評価される関数を考えてみよう。
純粋な関数でもロジックを表現することは可能だが、if文のネストが深くなればなるほど地獄である。手続き型言語であれば早期リターンで書きたいところだが、関数型言語ではどうするのか。

方法1. Eitherモナドを使う

※某所で指摘を受けたので追記。
Either モナド自体の性質を利用すれば、無尽蔵にネストが深くなっていく状況は避けることができる。場合によってはこれで十分だろう。ただ、より早期リターン風に表現したいときどうしたらよいか?

ついでにApplicativeスタイルでの記述も載せておく。

方法2. 継続モナドを使う

そこで継続モナド登場。純粋関数内で、早期リターンのような記述が可能となる。

全部のせておく。

自作のHaskellアプリ(AHA & Bingo)を stack 対応した話

巷で話題の Haskell のビルドツール stack だが、自作のアプリも stack でのビルドに対応してみた。

https://github.com/mitsuji/aha
https://github.com/mitsuji/bingo

stack の便利さをどう表現しようか。筆者の場合は git に出会ったときと状況が似ていると感じている。

ソースコード管理の重要さを知りながらも、cvs や subversion を「どうしても使わなければ」と思うことはなかったが、git に出会ってからは git というツールとともにソースコード管理そのものも、ちょっとしたものを作るときでもあたりまえのこととして受け入れるようになった。

stack の場合は、自分のソースをパッケージとして組むことをあたりまえのこととしてくれるツールという感じがする。

stack は 依存ライブラリと依存コンパイラ(ghc)のバージョンをまとめて解決してくれるので、とてもありがたい。 scala の sbt に 影響を受けているようだが、sbtはさすがに jdk のバージョンも管理してくれるわけではないので stack の方が上を行っていると思う。

下記のコマンドで最新のghcが入る。

$ stack setup

プロジェクトに cd して下記のコマンドでプロジェクトがビルドできる。

$ stack build

プロジェクトに cd して下記のコマンドでプロジェクト内のソースを参照しつつREPL。

$ stack ghci

プロジェクトに cd して下記のコマンドで ~/.local/bin に 実効形式がインストールされる。

$ stack install

Haskell 入門の敷居がまた下がった。

Haskell is ready for industry !