2017-04-13 89 views
7

在F#的printf中,有格式说明符%A,它允许传入任何F#类型,并且它将被评估和打印。为什么Fam的printf中的%A说明符在OCaml的printf中不存在?

举个例子:

type Result<'a> = 
    | Failure 
    | Success of 'a  

printf "%A" (Success "hello") // prints out 'Success "hello"' 

哪里,显然,Result<'a>不是一个内置类型。

我可以在OCaml的声明类似的类型,但对于Printf.printf没有等价符 - 相反,我会实现我自己string_of_result功能,并在格式字符串中使用%s符。此外,由于这是一个多态类型,我将不得不创建一个不直观的函数,它可以处理任何类型的'a实例。

我的问题是 - 为什么OCaml缺乏这个方便的说明符?是否因为没有实施它的动机?是否因为有一些缺乏魔咒的魔咒,这只是在F#中?

回答

7

我会说“缺乏魔咒mojo”可能是原因。

在F#中,%A说明符将打印延迟到基于反射的打印机 - 它使用运行时类型信息来遍历和打印值。在这个过程中使用的反射API是一个特定于.NET的东西。此外,虽然方便,但它也是一个相对昂贵的机制 - 如果您可以使用更具体的机制,则不应将其用作全局说明符。

据我所知,OCaml没有相应的反射功能,可以在这里使用。也许还有另一种机制可以让你实现一个通用打印 - 但是我对OCaml内部知识不够熟悉。

6

在OCaml中执行此操作的常用方法是使用%a说明符,并为result写入(或派生)打印机以传递给它。

这可能是这样的:其中pp_result已被deriving条款产生

type 'a result = 
    | Success of 'a 
    | Failure 
[@@deriving show] 

Format.printf "%a" (pp_result Format.pp_print_string) (Success "hello") 

。请注意,pp_result将格式化功能用作打印任何'a s的参数。

OCaml在编译过程中会完全擦除类型(几乎),因此无法像F#中那样使用反射来实现自动打印功能。无论如何,对于抽象类型的语言来说,反射效果并不明显。

+0

正如一个补充:这个解决方案需要ppx处理 - 当我将代码复制并粘贴到REPL时,''pp_result'''仍然是未定义的。 –

+0

@ lambda.xy.x - 我也注意到了。出于某种原因,我已经通过'opam'安装了'ppx_deriving',但是现在抛出了一个错误:'找不到deriver show'。 – asafc

+1

是的,我不想让一个真正关于'printf'说明符的答案与构建/配置'ppx_deriving'的细节复杂化。 (参考:在顶层,'#use“topfind”',然后'#require“ppx_deriving.show”',但请参阅'ppx_deriving'文档了解详细信息。) – gsg

相关问题