いかさまdynamic typing in OCaml

さらに読者を混乱させてみる。

let to_dyn t x = (fst t) x
let of_dyn t x = (snd t) x
let int =
  (fun (i : int) -> `Int i),
  (fun (`Int i) -> (i : int))
let bool =
  (fun (b : bool) -> `Bool b),
  (fun (`Bool b) -> (b : bool))
let pair a b =
  (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 list a =
  (fun xs -> `List (List.map (to_dyn a) xs)),
  (fun (`List xs) -> List.map (of_dyn a) xs)
let rec print = function
  | `Int i -> string_of_int i
  | `Bool b -> string_of_bool b
  | `Pair (x, y) -> "(" ^ print x ^ ", " ^ print y ^ ")"
  | `List xs ->
      let rec prints = function
        | [] -> ""
        | [x] -> print x
        | y :: zs -> print y ^ "; " ^ prints zs in
      "[" ^ prints xs ^ "]"

使い方:

# let t = list (pair int bool) ;;
val t :
  ((int * bool) list ->
   [> `List of [> `Pair of [> `Int of int ] * [> `Bool of bool ] ] list ]) *
  ([ `List of [ `Pair of [ `Int of int ] * [ `Bool of bool ] ] list ] ->
   (int * bool) list) =
  (<fun>, <fun>)
# let d = to_dyn t [(1, true); (2, false); (-3, false)] ;;
val d :
  [> `List of [> `Pair of [> `Int of int ] * [> `Bool of bool ] ] list ] =
  `List
    [`Pair (`Int 1, `Bool true); `Pair (`Int 2, `Bool false);
     `Pair (`Int -3, `Bool false)]
# print d ;;
- : string = "[(1, true); (2, false); (-3, false)]"
# of_dyn t d ;;
- : (int * bool) list = [(1, true); (2, false); (-3, false)]

追記:拡張可能にしたりして、いよいよ混乱させてみる。

type 'a y = Y of ('a y -> 'a -> string)
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 ^ "]"
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 ^ ")"
# print2 (Y print2) d ;;
- : string = "[(1, true); (2, false); (-3, false)]"

追記の追記:しかも間違いをこっそりと直したり。(print1とprint2の最後の

  | x -> self (Y self) x

が不要だった。)