OCaml中是否有通用打印机可以检测类型?

时间:2019-01-07 15:25:25

标签: ocaml

我想打印一个包含不同元素的列表(出于教育目的)

我已经阅读了一个教程,该教程解释了如何在列表中存储不同的类型。

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 :(得分:2)

顶级打印机应该可以正常工作:

[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)