Exercises into dune project with ppx_deriving

Hello,

I’'m quite new to OCaml, and I’m trying the Exercises section on the site. Although it is really nice to use utop to have a quick view for what some code can do, I’m trying to extend some of those exercises into a project with some ideas to test.

I’m currently testing the modified run length encoding exercise, and trying to add some “pretty printing” with ppx_deriving on top of that.

For now my code looks something like this:

type 'a rle =
  | One of 'a
  | Many of int * 'a
  [@@deriving show]

let pp = pp_rle Format.pp_print_string
let show = show_rle Format.pp_print_string

let encode l =
  let tup c e =
    if c = 1 then One e
    else Many (c, e) in
  let rec f c acc = function
    | [] -> []
    | [x] -> (tup (c+1) x) :: acc
    | a :: (b :: _ as t) ->
      if a = b then f (c+1) acc t
      else f 0 ((tup (c+1) a) :: acc) t in
    List.rev (f 0 [] l)

let res = encode ["a"; "a"; "a"; "a"; "b"; "c"; "c"; "a"; "a"; "d"; "e"; "e"; "e"; "e"]

let print_listof_string_rle rles =
  Format.printf
    "@[<1>%a@]@.\n"
    Format.(pp_print_list
      ~pp_sep:(fun fmt () -> Format.fprintf fmt ";@ ")
      pp)
    rles

let a = One "a"

let () =
  print_listof_string_rle res;
  print_endline (show a)

It was a bit hard for me to come to this solution because I’m a beginner and Iearnt the hard way what this function signature is meaning:

(Format.formatter -> 'a -> unit) -> Format.formatter -> 'a rle -> unit

And although this works, I’m not really convinced about my print_listof_string_rle function because it has become a really specific function for string rle.

As I’m coming from a rather large pool of coding languages that aren’t functionnal, I am thinking (I may be wrong and accept that) that I could be able to create such function but a bit more generic, so that it would work for any 'a type inside the type 'a rle, by using ppx_deriving.show.

Is there a way to make that function more generic, and/or to detect what type (either basic or complex type) so it could apply the best formatter for the type?

Hi, and welcome !
You can’t “detect a type” as types are erased during the compilation and do not exist at runtime.
You can however remain more polymorphic by leaving the job of printing the 'a payload in your 'a rle values to some function passed as argument. Something like:

  let print_rle_list pp rles =
    Format.printf
      "@[<1>%a@]@.\n"
      Format.(pp_print_list
        ~pp_sep:(fun fmt () -> Format.fprintf fmt ";@ ")
        (pp_rle pp)
      )
      rles

Also if you want your pretty-printer to remain composable, you should not use @. or \n in it, as that will reset the formatting engine. If you find yourself writing a lot of printers by hand, you could also look into the fmt to make that less painful.

1 Like