Variant mapping to string and back

Hey, suppose I have a variant type


type basic_color =
  | Black
  | Red
  | Green
  | Yellow
  | Blue
  | Magenta
  | Cyan
  | White
let to_string = function
  | Black -> "1"
  | Red -> "2"
  | Green -> "3"
  | Yellow -> "4"
  | Blue -> "5"
  | Magenta -> "5"
  | Cyan -> "6"
  | White -> "7"

I want to have a function to map from strings back to the basic_color type. I was thinking to have a map in first place.


let l =
  [
    (Black, "1");
    (Red, "2");
    (Green, "3");
    (Yellow, "4");
    (Blue, "5");
    (Magenta, "5");
    (Cyan, "6");
    (White, "7");
  ]

However, I want to use the type system to make sure I didn’t miss any of the colors. E.g. I add another color to my variant type, and forget to update my association list.

What would be nice is to use polymorphic variants and then detect that linfers as having a subset rather than the complete set.

Otherwise, you can repeat the values in a list and then make assertions against that list. This requires repeating yourself, but you are repeating yourself in a different away and mechanically comparing these repetitions, which is also what tests do for a program in general. And if the reference repetition is right next to the type, it’s not so annoying to maintain.

type basic_color =
  | Black
  | Red
  | Green
  | Yellow
  | Blue
  | Magenta
  | Cyan
  | White

let basic_colors = [Black; Red; Green; Yellow; Blue; Magenta; Cyan; White]

let l =
  [
    Black, "1";
    Red, "2";
    Green, "3";
    Yellow, "4";
    Blue, "5";
    (*Magenta, "5";*)
    Cyan, "6";
    White, "7";
  ]

let () = assert (basic_colors = List.sort compare (List.map Pair.fst l))
1 Like

That’s a good point, thanks. There is enumerate ppx that allows to get the basic colors list.

open Core

type basic_color =
  | Black
  | Red
  | Green
  | Yellow
  | Blue
  | Magenta
  | Cyan
  | White
[@@deriving enumerate]


1 Like

Posting working solution :

open Core

type basic_color =
  | Black
  | Red
  | Green
  | Yellow
  | Blue
  | Magenta
  | Cyan
  | White
[@@deriving enumerate, sexp]

let to_string = function
  | Black -> "1"
  | Red -> "2"
  | Green -> "3"
  | Yellow -> "4"
  | Blue -> "5"
  | Magenta -> "6"
  | Cyan -> "7"
  | White -> "8"

let string_to_color =
  List.map all_of_basic_color ~f:(fun x -> (to_string x, x))
  |> Map.of_alist_exn (module String)

let of_string x = Map.find_exn string_to_color x

let%expect_test "variant" =
  let l = List.map all_of_basic_color ~f:(fun x -> (to_string x, x)) in
  print_s [%message (l : (string * basic_color) list)];
  [%expect
    {|
    (l
     ((1 Black) (2 Red) (3 Green) (4 Yellow) (5 Blue) (6 Magenta) (7 Cyan)
      (8 White)))
    |}];
  let c = of_string "4" in
  print_s [%message (c : basic_color)];
  [%expect
    {| (c Yellow) |}]