Reputation: 43
I'm trying to pretty print a custom record type that contains a Hashtable (using the Base standard library) in OCaml with ppx-deriving, but I need to implement Hashtbl.pp for it to work.
I've tried looking at examples online and the best one that I found is https://github.com/ocaml-ppx/ppx_deriving#testing-plugins, but I'm still getting strange type errors like "This function has type Formatter.t -> (string, Value.t) Base.Hashtbl.t -> unit. It is applied to too many arguments; maybe you forgot a `;'"
How do you extend the Hashtbl module with a pp
function?
Here is my code so far (Value.t is a custom type which I successfully annotated with [@@deriving show]:
open Base
(* Extend Hashtbl with a custom pretty-printer *)
module Hashtbl = struct
include Hashtbl
let rec (pp : Formatter.t -> (string, Value.t) Hashtbl.t -> Ppx_deriving_runtime.unit) =
fun fmt -> function
| ht ->
List.iter
~f:(fun (str, value) ->
Caml.Format.fprintf fmt "@[<1>%s: %s@]@." str (Value.string_of value))
(Hashtbl.to_alist ht)
and show : (string, Value.t) Hashtbl.t -> Ppx_deriving_runtime.string =
fun s -> Caml.Format.asprintf "%a" pp s
;;
end
type t =
{ values : (string, Value.t) Hashtbl.t
; enclosing : t option
}
[@@deriving show]
Upvotes: 4
Views: 803
Reputation: 35260
The type of the values
field of your record is a parametrized with two type variables, therefore the deriver is trying to use a general pp
function that is parametrized by the key and data pretty-printers, e.g., the following will enable show
for any hashtable (with any key and any value, as long as keys and values are showable,
module Hashtbl = struct
include Base.Hashtbl
let pp pp_key pp_value ppf values =
Hashtbl.iteri values ~f:(fun ~key ~data ->
Format.fprintf ppf "@[<1>%a: %a@]@." pp_key key pp_value data)
end
so you can finally define your type
type t = {
values : (string,Value.t) Hashtbl.t;
enclosing : t option;
} [@@deriving show]
However, I would suggest another approach that instead of creating a general Hashtable module, creates a specialized Values
module, e.g.,
module Values = struct
type t = (string, Value.t) Hashtbl.t
let pp ppf values =
Hashtbl.iteri values ~f:(fun ~key ~data ->
Format.fprintf ppf "@[<1>%s: %s@]@." key (Value.to_string data))
end
Now you can use it as,
type t = {
values : Values.t;
enclosing : t option;
} [@@deriving show]
If you still want a generic printable hash table, then I would advise against using the include
statement, but, instead, implement just the required printable interface for the ('k,'s) Hashtbl.t
type, e.g.,
module Hashtbl_printable = struct
type ('k,'s) t = ('k, 's) Hashtbl.t
let pp pp_key pp_value ppf values =
Hashtbl.iteri values ~f:(fun ~key ~data ->
Format.fprintf ppf "@[<1>%a: %a@]@." pp_key key pp_value data)
end
type t = {
values : (string, Value.t) Hashtbl_printable.t;
enclosing : t option;
} [@@deriving show]
Upvotes: 4