Pretty-распечатать Hashtbl в OCaml для работы с производными ppx - PullRequest
2 голосов
/ 14 января 2020

Я пытаюсь напечатать специальный тип записи, который содержит Hashtable (используя стандартную библиотеку Base) в OCaml с выводом ppx, но мне нужно реализовать Hashtbl.pp, чтобы он работал.

Я попытался просмотреть примеры в Интернете, и лучший из найденных мной вариантов - https://github.com/ocaml-ppx/ppx_deriving#testing -plugins , но я все еще получаю странные ошибки типа, такие как «Эта функция имеет тип Formatter.t -> ( string, Value.t) Base.Hashtbl.t -> unit. Применяется к слишком многим аргументам; возможно, вы забыли `; ''

Как расширить модуль Hashtbl с помощью функции pp ?

Вот мой код (Value.t - это пользовательский тип, который я успешно аннотировал с помощью [@@ diverving 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]

1 Ответ

2 голосов
/ 14 января 2020

Решение 1

Тип поля values вашей записи параметризован двумя переменными типа, поэтому производный пытается использовать общую функцию pp, которая параметризована ключом и data pretty-printers, например, следующее включит show для любой хеш-таблицы (с любым ключом и любым значением, пока ключи и значения отображаются,

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

, так что вы можете, наконец, определить свой тип

type t = {
  values : (string,Value.t) Hashtbl.t;
  enclosing : t option;
} [@@deriving show]

Решение 2 (рекомендуется)

Однако я бы предложил другой подход, который вместо создания общего модуля Hashtable создает специализированный модуль Values, например,

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

Теперь вы можете использовать его как

type t = {
  values : Values.t;
  enclosing : t option;
} [@@deriving show]

Решение 3

Если вы все еще хотите универсальный c пригодный для печати стол ha sh, то я бы посоветовал против используя оператор include, но вместо этого реализуйте только необходимый интерфейс для печати для типа ('k,'s) Hashtbl.t, например,

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]
...