昨日のつづき

「動的型」(type dynamic)は拡張可能でないといけないので、拡張可能な型の値として、多相バリアントのかわりに例外をつかってみました。これならStandard MLも安心。

ちなみにYが必要なのは、printを拡張可能にするためにはopen recursionが必要で、そのためには自己適用が必要で、そのためには再帰型が必要だからです。

type dyn = exn
type 'a typ = ('a -> dyn) * (dyn -> 'a)
let to_dyn t x = (fst t) x
let of_dyn t x = (snd t) x
type 'a y = Y of ('a y -> 'a -> string)

exception Int of int
let int : int typ =
  (fun i -> Int i),
  (fun (Int i) -> i)
exception Bool of bool
let bool : bool typ =
  (fun b -> Bool b),
  (fun (Bool b) -> b)
exception List of dyn list
let list (a : 'a typ) : 'a list typ =
  (fun xs -> List (List.map (to_dyn a) xs)),
  (fun (List xs) -> List.map (of_dyn a) xs)
let print1 (Y self) = function
  | Int i -> string_of_int i
  | Bool b -> string_of_bool b
  | List xs ->
      let rec prints = function
        | [] -> ""
        | [x] -> self (Y self) x
        | y :: zs -> self (Y self) y ^ "; " ^ prints zs in
      "[" ^ prints xs ^ "]"

(* 後から「拡張」したつもり *)
exception Pair of dyn * dyn
let pair (a : 'a typ) (b : 'b typ) : ('a * 'b) typ =
  (fun (x, y) -> Pair (to_dyn a x, to_dyn b y)),
  (fun (Pair (x, y)) -> (of_dyn a x, of_dyn b y))
let print2 (Y self) = function
  | (Int _ | Bool _ | List _) as x -> print1 (Y self) x
  | Pair (x, y) -> "(" ^ self (Y self) x ^ ", " ^ self (Y self) y ^ ")"
# let t = list (pair int bool) ;;
val t : (int * bool) list typ = (<fun>, <fun>)
# let d = to_dyn t [(1, true); (2, false); (-3, false)] ;;
val d : dyn =
  List
   [Pair (Int 1, Bool true); Pair (Int 2, Bool false);
    Pair (Int (-3), Bool false)]
# print2 (Y print2) d ;;
- : string = "[(1, true); (2, false); (-3, false)]"