Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
OCaml中是否有检测类型的通用打印机?_Ocaml - Fatal编程技术网

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

OCaml中是否有检测类型的通用打印机?,ocaml,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 | st

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

我读过一篇教程,解释了如何在列表中存储不同的类型

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顶层知道每个变量的类型,并且总是以正确的格式显示类型:我可以调用这个打印机吗

是否有一种仅适用于toplevel的解决方案,我们可以使用
#install_打印机安装


我知道编译器在通过类型检查后会丢弃类型信息。

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

[1; "one"; 1.];;
- : (int -> string -> float -> unit) list =
(::) (1, (::) ("one", (::) (1., [])))
(由于确保toplevel打印的值可以复制粘贴回顶级并产生相同的值,因此打印不理想是一个不幸的结果)

但这只能在语言本身之外实现:顶级打印机可以检查打字环境,而这在语言本身中是不可能的。实际上,像
typeof
这样的函数会破坏参数性。因此,OCaml中没有通用打印机功能(不查看内部内存表示),也没有通用异构列表打印机

如果要打印异构列表,有三种可能的路径:

  • 打印特定类型的异构列表

    let print_concrete ppf (x::y::z::rest) = Format.fprintf ppf "%f %f %f" x y z
    
    (与外观相反,此函数是total:其类型使其无法在少于三个元素的列表上使用)

  • 使用异类列表,这些列表总是将打印功能打包在其主值上

    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)

谢谢你的回答,我同意打印的格式应该是可复制的。但是异构列表有两个语法,所以
[1;“one”1.]
可以像
-:(int->string->float->unit)list=1::“one”:[]
您的第一个解决方案非常好,但我搜索了与toplevel类似的内容:因为他现在可以打印类型(使用构造函数表单)。与第一个解决方案相反,解决方案2和3适用于所有长度的列表:但我必须记住我添加到列表中的数据类型,并添加正确的打印机。我已了解到0和false具有相同的内部表示形式,因此我们如何构建通用打印机?我还知道变量类型的变量是存储的:我必须做一个这样的列表
int3::Char'r'::String“e”::[]
我们如何检查顶层的键入环境?也许我可以制作一些神奇的东西,或多或少地完成toplevel所做的事情(它可以打印任何变量,包括变量类型)。您可以使用inspect,例如
inspect.Sexpr.dump(Obj.repr[1;“one”;[])
产生:
(dump(BLK/0:TAG 0:VALUES 1)(BLK/1:TAG 0:VALUES(STR/2:LEN 3“one”)(BLK/3:TAG 0:VALUES 0 0))
dump\u with_formatter
可用于获取字符串:
Format.asprintf“%a”Inspect.Sexpr.dump\u with_formatter(Obj.repr[1;“one”])