Skip to content

Instantly share code, notes, and snippets.

@ENAML
Last active February 5, 2019 04:21
Show Gist options
  • Save ENAML/916b99525ae7ad0ce99c7ce8396e6858 to your computer and use it in GitHub Desktop.
Save ENAML/916b99525ae7ad0ce99c7ce8396e6858 to your computer and use it in GitHub Desktop.
Ocaml Stringifier GADT
(* Stringify (WIP)
------------------------------------------------------------------
Generic, type-safe [to_string] utility.
Made for fun while reading about GADTs in Ocaml :-)
GADT References:
- https://en.wikipedia.org/wiki/Generalized_algebraic_data_type
- https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s%3Agadts
- https://blog.janestreet.com/why-gadts-matter-for-performance/
Usage Examples:
[to_string (Tup2(String, Int)) ("hello", 1)]
[to_string (List (Tup1 Int)) [1; 2; 3;]]
TODO:
- Add [Record] type
*)
(* GADT type *)
type _ typ =
| Int : int typ
| Float : float typ
| Bool : bool typ
| Char : char typ
| String : string typ
| Tup1 : ('a typ) -> ('a typ)
| Tup2 : ('a typ * 'b typ) -> ('a * 'b) typ
| Tup3 : ('a typ * 'b typ * 'c typ) -> ('a * 'b * 'c) typ
| Tup4 : ('a typ * 'b typ * 'c typ * 'd typ) -> ('a * 'b * 'c * 'd) typ
| Option : ('a typ) -> ('a option typ)
| List : ('a typ) -> ('a list) typ
| Array : ('a typ) -> ('a array) typ
(* String creator fn *)
let rec to_string
: type t. t typ -> t -> string
= fun t x ->
match t with
| Int -> string_of_int x
| Float -> string_of_float x
| Bool -> string_of_bool x
| Char -> String.make 1 x
| String -> Printf.sprintf "%S" x
| Tup1 t1 -> Printf.sprintf "(%s)" (to_string t1 x)
| Tup2(t1, t2) ->
let (x1, x2) = x in
Printf.sprintf "(%s, %s)" (to_string t1 x1) (to_string t2 x2)
| Tup3(t1, t2, t3) ->
let (x1, x2, x3) = x in
Printf.sprintf "(%s, %s, %s)"
(to_string t1 x1) (to_string t2 x2) (to_string t3 x3)
| Tup4(t1, t2, t3, t4) ->
let (x1, x2, x3, x4) = x in
Printf.sprintf "(%s, %s, %s, %s)"
(to_string t1 x1) (to_string t2 x2) (to_string t3 x3)
(to_string t4 x4)
| Option t1 ->
begin match x with
| Some x1 -> Printf.sprintf "Some %s" (to_string t1 x1)
| None -> "None"
end
|> Printf.sprintf "(%s)"
| List t1 ->
let str_list = x |> List.map (fun x_i -> to_string t1 x_i) in
Printf.sprintf "[%s]" (String.concat "; " str_list)
| Array t1 ->
let str_array = x |> Array.map (fun x_i -> to_string t1 x_i) in
let str_list = Array.to_list str_array in
Printf.sprintf "[|%s|]" (String.concat "; " str_list)
(* Examples *)
let () = begin
let t = List(Tup2(String, Int)) in
let x = [("one", 1); ("two", 2); ("three", 3)] in
to_string t x
|> print_endline
end
(* prints: "[("one", 1); ("two", 2); ("three", 3)]" *)
let () = begin
let t = List(Option(String)) in
let x = [Some "one"; None; Some "three"] in
to_string t x
|> print_endline
end
(* prints: "[(Some "one"); (None); (Some "three")]" *)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment