Concurrent Clean : カリー化と効率

add :: !Int !Int -> Int
add x y = x + y

add :: !Int -> (Int -> Int)
add x = \y = x + y

を区別する理由を書こうかと思ったのですが、ここを読んでいる人にとってはあたりまえのことになりそうだったので、省略。
要は、低レベルでの関数のアリティが知りたいということと、Cleanではエクスポートする関数は定義モジュールファイルに関数の型宣言だけを記述するというスタイルであるということがポイントでした。

Concurrent Clean : 正格性注釈

酒井さんのふりに反応してみようかと。
これまで、Cleanについては型理論な方面について論文をチェックしたりしてきたわけではないので、私の説明は多分に感覚的なものになるのですが。
Cleanの正格性注釈は、新たな型を作り出しているのではなく、式が評価されるコンテキストを指定しているので、「a -> b」と「!a -> b」とはサブタイプ関係ではなく同一の型になります。
そもそも、Cleanでは、関数定義に添えられる型指定は、型そのものではなく、関数宣言の一部として特別なフォーマットを持った表現になっていて、その表現の一部に正格性注釈が記述できるという性質のものなのです。
つまり、

add :: !Int !Int -> Int
add x y = x + y

という記述をCleanの関数定義では行いますが、これを

add :: !Int -> !Int -> Int
add x y = x + y

のように記述することはできません。
しかし、

add :: !Int -> (Int -> Int)
add x = \y = x + y

のように記述することはできます。
Cleanの関数宣言は、このような定義の違いを、型指定の記述に反映させていて、コンパイル時にはこの情報を用いて必要な最適化を行っているのです。
また、正格性の注釈は関数宣言の引数にしか指定することはできず、

add :: !Int -> (!Int -> Int)
add x = \y = x + y

のように書いても、2つ目の正格性注釈は無視されます。正格性注釈は、あくまで関数呼び出しでのコンテキストを指定しているだけであって、型指定ではないからです。

      • -

ちょっと急いで書いたので、雑ではありますが、ひとまずこんなところで。