Есть ли в OCaml универсальный принтер, который определяет тип? - PullRequest
0 голосов
/ 07 января 2019

Я хочу напечатать список с другим элементом в нем (для образовательных целей)

Я прочитал учебник, который объясняет, как хранить различные типы в списке.

type _ list =
    [] : unit list
  | ( :: ) : 'b * 'a list -> ('b ->'a) list;;
1 :: "e" :: 'r' :: [];; (* this is allowed *)

как я могу сделать что-то вроде этого псевдокода:

match typeof(my_expr) with
  int -> print_int
| string -> print_string

у нас будет напечатано «1, e, r». Некоторые решения, которые я искал

  • Измените мой тип в тексте и напечатайте его
  • Использовать другое определение типа, может быть ('a,' b) список?

Я спрашиваю это, потому что OCaml должен знать тип каждой переменной и всегда показывать тип в правильном формате: я могу вызвать этот принтер?

Существует ли решение только для верхнего уровня, которое мы можем установить с #install_printer?

Я знаю, что компилятор сбрасывает информацию о типе после прохода проверки типа.

1 Ответ

0 голосов
/ 07 января 2019

Принтер верхнего уровня должен работать нормально:

[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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...