Ocaml';s sprintf没有';无法使用%a格式说明符

Ocaml';s sprintf没有';无法使用%a格式说明符,ocaml,format-specifiers,Ocaml,Format Specifiers,似乎sprintf在其格式说明符中不允许%a。是这样吗?如果是这样的话,为什么会这样?是否有解决办法 示例。我有一个长而复杂的数据类型: type t = Foo | Baz 对于这种类型,我有一台漂亮的打印机,它将其值的字符串表示形式发送到任意的输出通道: let pp_t oc = function | Foo -> fprintf oc "Foo" | Baz -> fprintf oc "Baz" 如果我写 let _ = printf "%a=%d" pp_t

似乎
sprintf
在其格式说明符中不允许
%a
。是这样吗?如果是这样的话,为什么会这样?是否有解决办法

示例。我有一个长而复杂的数据类型:

type t = Foo | Baz
对于这种类型,我有一台漂亮的打印机,它将其值的字符串表示形式发送到任意的
输出通道

let pp_t oc = function
  | Foo -> fprintf oc "Foo"
  | Baz -> fprintf oc "Baz"
如果我写

let _ = printf "%a=%d" pp_t Foo 2

然后一切正常——消息“Foo=2”按预期出现在我的stdout或stderr上。但是如果我写

let s = sprintf "%a=%d" pp_t Foo 2
然后我得到了一个编译错误,抱怨参数
pp\u t
的类型是
out\u channel->t->unit
,但表达式的类型应该是
unit->'a->string

难道不能在
sprintf
的格式说明符中使用
%a
吗?

简短回答 使用
Format
模块进行漂亮的打印,使用
Format.asprintf
函数而不是
sprintf
构建字符串(我通常只在文件开头使用
open Format

长话短说 可以将
%a
转换规范与
sprintf
一起使用。但是,所需函数的类型不同于
Printf.fprintf
Printf.Printf
所需的类型

所有漂亮的打印机(满足
%a
转换所需的值类型的函数)都以其类型对输出类型进行编码。因此,对于不同系列的
printf
函数,您需要使用不同的漂亮打印函数

对于
格式
模块,您需要类型为
格式化程序->'a->unit
的函数。这也是顶级和调试器所需的类型,也是最常见的漂亮打印函数类型(Core等库以及许多其他库提供了满足此签名的漂亮打印机)。
Format
模块还提供了
asprintf
函数,该函数与
sprintf
函数不同,可以很好地处理
%a
转换(即,它具有相同的
格式化程序->'a->unit
类型)

Printf.Printf
的情况下,漂亮打印机的类型应该是
out\u channel->'a->unit
。这种类型的通用性要差得多,因此比这种格式的通用性要差得多。很少有图书馆提供这种服务

最后,
Printf.sprintf
函数需要类型为
unit->'a->string
的打印机。通常,获得如此漂亮打印机的唯一方法是手动编写(有时使用
Printf.asprintf
)。在您的情况下,它将是:

let pp_t () = function
  | Foo -> "Foo"
  | Baz -> "Baz"
简短回答 使用
Format
模块进行漂亮的打印,使用
Format.asprintf
函数而不是
sprintf
构建字符串(我通常只在文件开头使用
open Format

长话短说 可以将
%a
转换规范与
sprintf
一起使用。但是,所需函数的类型不同于
Printf.fprintf
Printf.Printf
所需的类型

所有漂亮的打印机(满足
%a
转换所需的值类型的函数)都以其类型对输出类型进行编码。因此,对于不同系列的
printf
函数,您需要使用不同的漂亮打印函数

对于
格式
模块,您需要类型为
格式化程序->'a->unit
的函数。这也是顶级和调试器所需的类型,也是最常见的漂亮打印函数类型(Core等库以及许多其他库提供了满足此签名的漂亮打印机)。
Format
模块还提供了
asprintf
函数,该函数与
sprintf
函数不同,可以很好地处理
%a
转换(即,它具有相同的
格式化程序->'a->unit
类型)

Printf.Printf
的情况下,漂亮打印机的类型应该是
out\u channel->'a->unit
。这种类型的通用性要差得多,因此比这种格式的通用性要差得多。很少有图书馆提供这种服务

最后,
Printf.sprintf
函数需要类型为
unit->'a->string
的打印机。通常,获得如此漂亮打印机的唯一方法是手动编写(有时使用
Printf.asprintf
)。在您的情况下,它将是:

let pp_t () = function
  | Foo -> "Foo"
  | Baz -> "Baz"

为了避免在格式化函数中显示特定的数据类型,您应该始终使用
格式
模块,并为您的类型设计具有签名的漂亮打印机
val pp_t:Format.formatter->t->unit
;这也是toplevel要求为您的数据类型安装带有
#install_printer
的自定义打印机的签名


有了这样一个功能,您就可以简单地使用
%a“

为了避免格式化功能中出现特定的数据类型,您应该始终使用
格式
模块,并为具有签名
val pp\t:Format.formatter->t->unit
的类型设计漂亮的打印机;这也是toplevel要求为您的数据类型安装带有
#install_printer
的自定义打印机的签名

配备了此功能后,您只需使用
“%a”