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(最新版)では未実装だ。