Concurrent Clean : Existential Type & Dynamic

の便利な使い方を考え中。とりあえず、とても昔に下のような記事を書いていて、
http://www.geocities.jp/lethevert/softwares/clean/oop02.html#polymorphic_list
そこで、Existential Typeを使っている。(内容は、昔の記事なので、いろいろ突っ込みたいところがあるのですが・・・)
で、それを見ながら、

::A = I Int | R Real | S String

のようにVariantとして宣言する代わりに

::A = E.a: A a

と書くと、あらゆる型を含むことができる型を宣言できる。次のようなプログラムを書くと、

Start = [A 1, A 2.3, A 'a', A True, A "bcde"]

次のような出力になる。

[(A 1),(A 2.3),(A 'a'),(A True),(A "bcde")]

しかし、elimination ruleが書けない。

Start = map f [A 1, A 2.3, A 'a', A True, A "bcde"]
  where
    f (A a) = a

のようなプログラムは、あたりまえだが、型エラーになる。

      • -

前の記事では、

::A = E.a: {a::a, str::a -> String}
toA :: a -> A | toString a
toA a = {a=a, str=toString}

というように、レコード型を使ってeliminationのための関数を始めに登録してやる(その際に、型クラスを使って多相的にintroduction関数を用意してやると便利)ということを書いていて、これを使えば、

Start = map f [toA 1, toA 2.3, toA 'a', toA True, toA "bcde"]
  where
    f {a,str} = str a

というように書ける。(intruduction関数を用意するのが多少手間だが、これはlispのマクロのように、syntaxを追加するような機構があればclass宣言から自動的に導出できるはず)

      • -

それとは別に、同じようなことを、先に書いたDynamicのように、ExtensibleなVariantを使って同じようなことを表現することもできる。

Start = (ls, map f ls)
  where
    ls = [dynamic 1, dynamic 2.3, dynamic 'a', dynamic True, dynamic "bcde"]

f :: Dynamic -> String
f (_::Int)    = "Int"
f (_::Real)   = "Real"
f (s::String) = s
f _           = "Other"

DynamicはExistential Typeとは違って、「(変数::型名)」という形式でeliminateすることができる。
当然、

f (x::a | toString a) = toString x

という記述はしたくなるが、これはClean 2.1.1(最新版)では未実装だ。