Last active
February 5, 2019 04:21
-
-
Save ENAML/916b99525ae7ad0ce99c7ce8396e6858 to your computer and use it in GitHub Desktop.
Ocaml Stringifier GADT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* 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