Принтер верхнего уровня должен работать нормально:
[1; "one"; 1.];;
- : (int -> string -> float -> unit) list =
(::) (1, (::) ("one", (::) (1., [])))
(Неоптимальная печать является печальным следствием того, что значения, напечатанные на верхнем уровне, могут быть скопированы обратно на верхний уровень и выдают то же значение)
Но это возможно только за пределами самого языка: принтеры верхнего уровня могут проверять среду ввода, которая целенаправленно невозможна в самом языке. Действительно, такие функции, как typeof
, могут нарушить параметричность. Таким образом, в OCaml нет универсальной функции принтера (без учета представления внутренней памяти) и универсального принтера для разнородных списков.
Если вы хотите напечатать гетерогенный список, есть три возможных пути:
печать определенного типа гетерогенного списка
let print_concrete ppf (x::y::z::rest) = Format.fprintf ppf "%f %f %f" x y z
(В отличие от внешнего вида эта функция является полной: ее тип делает невозможным использование в списках, содержащих менее трех элементов)
Используйте гетерогенные списки, которые всегда упаковывают функцию печати вдоль своего основного значения
type 'a printer = Format.formatter -> 'a -> unit
type _ showable_list =
| [] : unit showable_list
| (::):
('a * 'a printer) * 'b showable_list
-> ('a -> 'b) showable_list
let rec print: type a. a showable_list printer =
fun ppf l -> match l with
| [] -> ()
| (a,printer) :: rest -> Format.fprintf ppf "%a@ %a" printer a print rest
предоставить соответствующий гетерогенный список функций печати
type 'a plist =
| []: unit plist
| (::): 'a printer * 'b plist -> ('a -> 'b) plist
let rec print: type l. l plist -> l list printer = fun printers ppf values ->
match printers, values with
| [], [] -> ()
| p :: prest, a :: rest -> Format.fprintf ppf "%a@ %a" p a (print prest) rest
Тот факт, что вам часто нужно специализировать гетерогенный тип списка, может стоить представить функтор для их генерации:
module Hlist(Specialization: sig type 'a t end) = struct
open Specialization
type 'a list =
| []: unit list
| (::): 'a t * 'b list -> ('a -> 'b) list
end
тогда предыдущий специализированный тип может быть построен с помощью
module Showable_list = Hlist(struct type 'a t = 'a * 'a printer end)
module Printer_list = Hlist (struct type 'a t = 'a printer end)