純粋関数型言語のfoldlで副作用を起こす

http://d.hatena.ne.jp/i_k_b/20120215/1329320486に触発されてCleanでも書いてみました。

module foldout
import StdEnv

// 出力する関数 (Fileは一意でなければならない)
// class (<<<) infixl a :: !*File !a -> *File

msg :== ["hello,", " uniqueness", " typing!", "\n"]

Start w # (cout, w) = stdio w
          cout = foldl (<<<) cout msg // side effect caused by foldl !
		/*
          cout = cout <<< "hello,"
          cout = cout <<< "uniqueness typing!"
         */
          (ok,w) = fclose cout w
        = w

実行結果

hello, uniqueness typing!

普通のfoldlに副作用を起こす関数(<<<)を渡せていますね。

解説

Cleanでは副作用を一意性型付け(uniqueness typing)によって扱います。
これをどのように表すかというと、型への 一意性を表す修飾(*) の有無で区別します。

この修飾はCleanコンパイラによって推論されるので、普通に副作用を含む式を書いていくとコンパイラが正しく修飾(と検査)を行ってくれます。


ところでこの修飾は式毎(= 使われる場所ごと)に行われるので、純粋なつもりで書いてある関数でも、途中で参照が共有されていなければ、安全に副作用を含む関数を渡すことが出来ます。
つまり副作用あり版と無し版をそれぞれ定義する必要がありません!スゴイね!