iTask版Cleanの機能

あけましておめでとうございます. 今年もよろしくお願いします.

新年一発目からCleanネタで行きます.


昨年末にリリースされたClean2.3ですが,
前バージョンの2.2以外にも, 以前からiTaskというワークフロー記述システム*1の最新版専用に用意されたバージョンのClean環境(以下iTask版)があります.
そっちの機能を紹介します. (まともな説明は多分他のどこにもない)

新機能1: 型クラスの集合に名前が付けられる

これは型文脈に記述する, 「クラスAでかつクラスBです」みたいな内容に名前を付けられる機能です.
まあ見た方が速い.

 :: AandB a = CA a & CB a

この記述によって, 「AandBをインスタンス化するには, 型クラスCAとCBのインスタンスであること」という制約(条件?)記述することが出来ます.

使ってみるとこんな感じ.

// 従来の方法1(ver2.3)
funcF :: a -> b | CA a & CB a // 直に書く
// 従来の方法2(ver2.3)
class AandB a | CA a & CB a  // クラスを定義して
funcF :: a -> b | AandB a
instance AandB Int;          // インスタンス化を列挙
instance AandB Char;
instance AandB Real;
...
// 新機能使用(iTask版)
funcF :: a -> b | AandB a    // これだけ

地味にうれしい機能ですね.

新機能2: Genericのスーパークラスをderivingできる

Clean2系ではGenericという機能が使えます. GHC(Haskellの方)にも入る予定だそうです.
Genericの詳細は(自分もよく分からんので)省くとして,適当に言えばC++のテンプレートに対応すると思います.
つまりGenericな関数を使うには, テンプレートのインスタンス化のように, derive式によってコードの生成をを指示する必要があります.

// 例: リスト, 2タプル, 3タプルを比較するgeneric関数を作る指示
derive gEq [], (,), (,,)

このGenericで指定した型文脈に名前をつけて(=スーパークラスを定義して)いる場合,
サブクラスのderivingをいちいち列挙するのがメンドクサイので解消したよ. というのがこの新機能.

従来の記述
generic gCA a :: ...
generic gCB a :: ...
generic gCC a :: ...
class AandBandC a | gCA{|*|} a & gCB{|*|} a & gCC{|*|} a

こんな定義があったとき, クラスAandBandCを, Int, Char, Realのそれぞれでインスタンス化しようとすると,

derive gCA Int, Char, Real
derive gCB Int, Char, Real
derive gCC Int, Char, Real	// それぞれでderiving
// さらに
instance AandBandC Int
instance AandBandC Char
instance AandBandC Real    // 型クラスをインスタンス化

こんな感じで, サブクラスの関数をスーパークラスの都合に合わせて手動でインスタンス化する必要がありました.

新機能を使った記述

上の例がiTask版では

// ここでAandBandCのインスタンス化をして, 同時にサブクラスのderivingもする!
derive class AandBandC  Int, Char, Real

これだけで済みます.
型クラスをderive式に渡すと, サブクラスも自動でderivingしてくれるわけですね!


[ただしこれを使うと, derivingの指定が他の箇所と被った場合コンパイルエラーになります.
上の例で言うと, generic関数gCAが既にIntについてのderiveをデフォルトで指定していたりするとアウトです.
何度指定しても同じものが生成されるはずなので許して欲しいんですけど….]

まとめ

なぜClean2.3にこの機能が入ってないの. なんなの!?

*1:でいいのか?