user-defined printer in OCaml

大城市里の小女人 提交于 2019-12-08 17:12:11

问题


printf, fprintf, etc. : all accept the %a conversion.

The manual says for %a:

"user-defined printer. Takes two arguments and apply the first one to outchan (the current output channel) and to the second argument. The first argument must therefore have type out_channel -> 'b -> unit and the second 'b. The output produced by the function is therefore inserted in the output of fprintf at the current point."

I can't understand what a user-defined printer is for, and how you would implement and use it. Can someone explain the motivation and maybe provide an example?

For example, when you want to, say, print a complex data-structure, why is it not possible to just print the data-structure with a custom function directly to a string or to output?


回答1:


If you have a function ty -> string you can use it with "%s" to print your data, so I think in realistic cases you can "just print your data structure". It might be a stylistic choice to use "%a" instead. It does seem more consistent in some ways.

On a 32-bit system, strings are limited to around 16MB in length. So you could imagine a case where the "%a" would work while "%s" would fail: if the intermediate string is longer than this. I've never had this come up in practice, though. I just use "%s", myself.




回答2:


What do you mean by "just print the complex data-structure"? You can do that once you defined a function converting your data-structure to string. It's also possible to "dump" the data-structure with a "default representation" (see, http://caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=139) but that's more for debugging than anything else.

Having said that; a very simple example for %a:

type ty = A | B

let ty_to_string = function
  | A -> "A"
  | B -> "B"

let print_ty chan v = output_string chan (ty_to_string v)

let _ = Printf.printf "%a" print_ty A



回答3:


Using %a allows the printing to go directly to the output channel, as opposed to "%s" and stringifying the value you want to print and then printing it.

The distinction seems to be entirely a matter of efficiency - why allocate a potentially large string (or use a buffer, with its exponential resizing and copying) when it's both possible and reasonable to send the serialized data directly to the output channel? Jeffrey points out quite correctly that very large serializations could fail on 32-bit systems because of string length.

I use %a often in my code, using Batteries' composable printing functions to build custom printers for my values:

let range_print oc r = 
  let print_one oc (a,b) = fprintf oc "%d:%d" a b in
  List.print ~first:"" ~last:"" ~sep:"," print_one oc r
let print_rule print_pred print_dec oc r = 
  fprintf oc "%a,%a" print_pred r.pred print_dec r.dec
let print_item oc x = print_rule range_print Int.print oc x in
...
printf "IN : %a\nOUT: %a\n" print_item a print_item b;


来源:https://stackoverflow.com/questions/6593616/user-defined-printer-in-ocaml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!