SMLでtype erasureできた
型に厳しいことで有名な言語であるStandard MLで
C++でよく使われる,type erasure(型消去)パターンを実現する方法を紹介します.
(* 斉藤さんのコメントによる指摘を受けて追記 *) fun op $ (f,x) = f x; infixr 1 $;
(* コード中の行頭に - の付いた行はインタプリタの出力です *)
準備
まず下準備から…(というかコレが一番のキモなんですけど)
signature ANY = sig type dyn val newdyn : unit -> ('a->dyn) * (dyn->'a) end
まずANYインターフェースを定義します.
で, 次にその実装.
structure Any :> ANY = struct exception Dynamic type dyn = exn (* exn => 例外 *) fun newdyn () = let exception E of 'a (* 型構築子Eを定義 *) in (E, fn (E a)=>a | _=> raise Dynamic) end end
えー. こんなんアリなんですかね?(汗
呼び出すたびに多相な例外型のコンストラクタと値の取得関数を返します.
SML黒魔術ですね.
次に型注釈を書いて**runtime用の型を表す値**を定義.
type 'a Any = ('a->Any.dyn)*(Any.dyn->'a) (* コメントの指摘を受けてtypo修正 *) val int_type = newdyn () : int Any val string_type = newdyn () : string Any val is_type = newdyn () : (int*string) Any
使ってみる
先に定義した3つの型に対応したジェネリックtoStringを定義.
fun IStoString (x,y) = String.concat ["(",Int.toString x,",",y,")"] fun gToString v = Int.toString $ snd int_type v handle Dynamic => snd string_type v (* !? *) handle Dynamic => IStoString $ snd is_type v - val it = fn : Any.dyn -> string
………汗
実際に適用すると….
val xs = [fst int_type 314 ,fst string_type "foobar" ,fst is_type (98, "hoge")] - val xs = [-,-,-] : Any.dyn list (* 怪しげなリスト *) val ss = List.map gToString xs - val ss = ["314","foobar","(98,hoge)"] : string list
やりました\(^o^)/