Concurrent Clean : 副作用とログ

純粋関数型で、最初に途方にくれるのは、ログの埋め込みだ。実際、最近まで途方にくれていた。
プログラムの深いところで(主にデバッグ目的だが)ログを取りたいと思ったとき、そのためだけに*Worldや*Fileを引数渡しで届けるようにプログラムを変更することは尋常ではない。参照透過もいいが、モジュール化にももうちょっと配慮してくれと叫びたくなる。
実は、Cleanでは、この問題は実にad-hoc(?)な方法で解決している。

stderr :: *File  //標準エラー出力向けファイルハンドラ
trace :: !msg .a -> .a | toString msg

という2種類の関数が用意されていて、traceは次のような意味合いの定義になっている。(http://sky.zero.ad.jp/~zaa54437/programming/clean/CleanBook/part1/Chap3.html#sc54より)

trace msg a
    #! f = fwrites msg stderr
    | 1<2 = const a f
          = abort "trace error"

これは、Cleanの評価プロセスと正格性アナライザの動作に依存した定義だが、実際上手く動く。
とはいえ、これは、デバッグ用だからこういう反則に近いことをしているわけで、普通のプログラミングでこれはあまりよくない。しかし、逆にいえば、デバッグという無視できない目的があっても、こういう方法しか提供できないということは、正攻法でこの問題を取り扱う適当な方法がないということを示している。