如何解决如何使用 OCaml 编译器打印表达式的内容
在使用编译器的 OCaml 中,我希望打印以下 3 个表达式的答案:
map (fun s -> s^"to") ["tak";"tok";"tek"] ;;
map (fun x -> x >= 0) [ 7 ; -13; -103; 79; 1230 ];;
map List.hd [ [false;false;true] ; [false;true;true]; [true;false;true]];;
当我使用 OCaml 顶级解释器时,我分别得到了所需的正确答案:
> map (fun s -> s^"to") ["tak";"tok";"tek"] ;;
> - : string list = ["takto"; "tokto"; "tekto"]
> map (fun x -> x >= 0) [ 7 ; -13; -103; 79; 1230 ];;
> - : bool list = [true; false; false; true; true]
> map List.hd [ [false;false;true] ; [false;true;true]; [true;false;true] ];;
> - : bool list = [false; false; true]
如何使用 OCaml 编译器复制它?我如何编写完成工作所需的打印说明?
解决方法
确实,OCaml 顶层 (REPL) 有一个通用打印机,在编译代码中不可用。
如果您刚刚开始使用 OCaml,我认为最好只是手动编写您自己的打印功能。这将使您专注于学习语言的基础知识,而不是扩展它的奇特方法。
例如,这是一个将字符串列表写出到标准输出的函数:
let print_strings sl =
let q s = "\"" ^ s ^ "\"" in
Printf.printf "[ %s ]\n" (String.concat "; " (List.map q sl))
当然,字符串是最简单的情况,因为它们已经可以打印了。但是您可以相当类似地处理其他情况。
有一种方法可以使用 Printf.printf "%b"
几乎1不可能,因为 OCaml 编译器将程序转换为二进制形式并擦除类型信息。换句话说,程序编译后运行时只看到机器整数,并没有关于这个整数是否应该被视为指向字符串、实整数、用户定义数据类型等的指针的信息.
事实上,对于许多编译语言来说都是如此,比如 C 或 C++。它们还要求用户提供用于打印其数据类型的特定函数,并在调用打印机时指定类型。
在 OCaml 中,我们通常使用 Format 模块中的 printf
函数进行打印。该函数与 C/C++ 中的同一个函数非常相似(除了它是类型安全的),例如,
open Format
let () =
printf "Hello,%s world\n%!" "cruel";
printf "Hello,%d times!\n%!" 42
如您所见,特殊格式说明符,如 %s
或 %d
指定参数的类型。所以 %d
需要一个 int
类型的参数,而 %s
需要一个 string
,%c
也有 char
,{{1 }} 为 %b
等等。此外,bool
说明符代表flush,它会立即将信息输出到控制台设备(否则可能会被缓冲)。
还有一个通用的 %!
说明符,它不需要一个参数,而是两个——一个函数,它将告诉如何打印参数,以及参数本身。它用于打印抽象类型的值,因此名称为 %a
。有一个约定,即定义抽象类型的模块还提供一个名为 %a
的函数,它指定应如何打印此值,例如,
pp
其中 let () = printf "Hello,abstract student %a\n%!" Student.pp s
模块可能定义为
Student
对于其他库提供的模块,您可以查找 struct Student : sig
type t
val create : string -> int -> t
val pp : Format.formatter -> t -> unit
end = struct
type t = {name : string; cls : int}
let create name cls = {name; cls}
let pp ppf {name; cls} =
Format.fprintf ppf "%s of %d" name cls
end
函数作为通用打印机。如果不存在,您也可以尝试将 pp
与 to_string
说明符一起使用。
%s
模块(它是 OCaml 标准库的一部分)带有一些帮助程序,例如,有一个 Format
函数可用于为列表制作打印机,例如,
pp_print_list
现在我们可以打印一个布尔值列表,
let pp_bool ppf x = fprintf ppf "%b" x
let pp_bools ppf xs =
pp_print_list pp_bool ppf xs
~pp_sep:(fun ppf () -> fprintf ppf ",");
会给我们,
printf "(%a)\n" pp_bools [true; false; true]
您可能会注意到,甚至对标准库中没有用于 (true,false,true)
的 pp
打印机这一事实感到恼火。你不是一个人!例如,您可能会发现 fmt 库 (Bool
) 使打印变得更加有趣。您还可以使用各种派生预处理器来为用户定义的类型派生打印机,请参阅文章末尾的链接。但这对于高级用途,对于初学者来说,您必须掌握格式库。
1) 真实的故事总是有点复杂。 OCaml 仍然通过使用值标记来保留一些信息,这使得诸如 genprintlib 之类的项目能够提供适用于任何对象的通用打印机,即使程序被编译为本地表示。这是一个相当老套的项目,它依赖于运行时的内部和未记录的功能,因此请谨慎使用它并仅用于调试。另见this discussion
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。