пользовательский принтер в OCaml - PullRequest
7 голосов
/ 06 июля 2011

printf, fprintf и т. Д.: Все принимают преобразование %a.

В руководстве сказано, что для %a:

"пользовательский принтер. Принимает два аргумента и применяет первый аргумент к outchan (текущий канал вывода) и ко второму аргументу.Поэтому первый аргумент должен иметь тип out_channel -> 'b -> unit, а второй - B. Выходные данные, создаваемые функцией, поэтому вставляются в выходные данные fprintf в текущей точке. "

Я не могу понять, для чего предназначен пользовательский принтер, и как бы вы его реализовали и использовали.Может кто-нибудь объяснить мотивы и, возможно, привести пример?

Например, если вы хотите, скажем, напечатать сложную структуру данных, почему невозможно просто напечатать структуру данных с помощью пользовательской функции непосредственно в строку или вывести?

Ответы [ 3 ]

5 голосов
/ 06 июля 2011

Что вы подразумеваете под «просто распечатать сложную структуру данных»?Вы можете сделать это, как только вы определили функцию, конвертирующую вашу структуру данных в строку.Также возможно «сбросить» структуру данных с «представлением по умолчанию» (см. http://caml.inria.fr/cgi-bin/hump.en.cgi?sort=0&browse=139), но это больше для отладки, чем для чего-либо еще.

Сказав это, очень простой пример для%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
2 голосов
/ 06 июля 2011

Если у вас есть функция ty -> string, вы можете использовать ее с "%s" для печати ваших данных, поэтому я думаю, что в реальных случаях вы можете "просто распечатать структуру данных". Это может быть стилистический выбор вместо использования "%a". Это кажется более последовательным в некоторых отношениях.

В 32-битной системе длина строк не должна превышать 16 МБ. Таким образом, вы можете представить себе случай, когда "%a" будет работать, а "%s" не удастся: если промежуточная строка длиннее этой. Я никогда не делал это на практике, хотя. Я просто использую "%s", сам.

1 голос
/ 11 июля 2011

Использование %a позволяет печатать непосредственно на выходном канале, в отличие от "% s" и строкового значения, которое вы хотите напечатать, а затем распечатать его.

Различие, по-видимому, целиком в эффективности - зачем выделять потенциально большую строку (или использовать буфер с экспоненциальным изменением размера и копированием), когда возможно и целесообразно отправить сериализованные данные непосредственно в выходной канал? Джеффри совершенно правильно указывает, что очень большие сериализации могут не работать в 32-битных системах из-за длины строки.

Я часто использую %a в своем коде, используя комбинируемые функции печати Батареи для создания пользовательских принтеров для моих значений:

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;
...