Spec-Zone.ru › OCaml

Модуль Format

module Format: sig .. end

Форматирование с pretty-printing.

Если вы впервые используете этот модуль, см. примеры ниже: examples.

Этот модуль реализует средства pretty-printing для форматирования значений внутри «блоков pretty-printing» и «семантических тегов» в сочетании с набором функций, подобных printf. Средство pretty-printing разбивает строки в заданных подсказках переноса и задаёт отступы в соответствии со структурой блоков. Аналогично, семантические теги позволяют отделить представление текста от его содержимого.

Это средство pretty-printing реализовано как надстройка над абстрактными форматтерами, которые предоставляют базовые функции вывода. Некоторые форматтеры предопределены, в частности:

  • Format.std_formatter выполняет вывод в stdout
  • Format.err_formatter выполняет вывод в stderr

Большинство функций модуля Format имеют два варианта: краткий, который работает со стандартным форматтером текущего домена, получаемым с помощью Format.get_std_formatter, и универсальный вариант с префиксом pp_, принимающий форматтер первым аргументом. Для варианта, работающего со стандартным форматтером текущего домена, вызов Format.get_std_formatter откладывается до получения последнего аргумента.

Дополнительные форматтеры можно создать с помощью Format.formatter_of_out_channel, Format.formatter_of_buffer, Format.formatter_of_symbolic_output_buffer или используя пользовательские форматтеры.

Предупреждение: поскольку форматтеры содержат изменяемое состояние, использование одного форматтера одновременно в нескольких доменах без синхронизации небезопасно для потоков. Это может привести к возникновению Invalid_argument или к неопределённому поведению.

Если несколько доменов выполняют запись в один канал вывода с помощью предопределённых форматтеров (полученных с помощью Format.get_std_formatter или Format.get_err_formatter), вывод из доменов будет перемежаться в точках сброса форматтеров, например при вызове Format.print_flush. Синхронизация не выполняется для форматтеров, полученных с помощью Format.formatter_of_out_channel (для стандартных каналов вывода и других каналов).

Введение

Этот модуль можно рассматривать как расширение средства printf, добавляющее автоматическое разбиение строк. Добавление аннотаций pretty-printing к обычным строкам формата printf позволяет задавать расширенные отступы и переносы строк. Аннотации pretty-printing описаны ниже в документации функции Format.fprintf.

Также можно использовать предоставляемые этим модулем функции явного управления блоками pretty-printing и вывода. Этот стиль проще, но многословнее, чем компактные строки формата fprintf.

Например, последовательность open_box 0; print_string "x ="; print_space ();
    print_int 1; close_box (); print_newline ()
, которая выводит x = 1 внутри блока pretty-printing, может быть сокращена до printf "@[%s@ %i@]@." "x =" 1 или ещё короче — до printf "@[x =@ %i@]@." 1.

Практические рекомендации для обычных пользователей этой библиотеки:

  • используйте простые блоки pretty-printing (получаемые с помощью open_box 0);
  • используйте простые подсказки переноса, получаемые с помощью print_cut (), которая выводит простую подсказку переноса, или с помощью print_space (), которая выводит пробел, обозначающий подсказку переноса;
  • после открытия блока pretty-printing выводите его содержимое с помощью базовых функций вывода (например, print_int и print_string);
  • после вывода содержимого блока pretty-printing вызывайте close_box (), чтобы закрыть блок;
  • по завершении pretty-printing сбросьте средство pretty-printing, чтобы вывести оставшееся содержимое, например выполните print_newline ().

Поведение команд pretty-printing не определено, если нет открытого блока pretty-printing. Каждый блок, открытый одной из приведённых ниже функций open_, необходимо закрыть с помощью close_box для корректного форматирования. В противном случае часть выведенного в блоках содержимого может не отобразиться или быть отформатирована неправильно.

При интерактивном использовании каждая фраза выполняется в исходном состоянии стандартного средства pretty-printing: после выполнения каждой фразы интерактивная система закрывает все открытые блоки pretty-printing, выводит весь ожидающий текст и сбрасывает стандартное средство pretty-printing.

Предупреждение: смешивать вызовы функций pretty-printing этого модуля с вызовами низкоуровневых функций вывода из Stdlib рискованно.

Функции pretty-printing помещают содержимое в очередь и стек средства pretty-printing, откладывая его вывод для вычисления корректных переносов строк. В отличие от них, базовые функции ввода-вывода записывают данные непосредственно в устройство вывода. В результате вывод базовой функции ввода-вывода может появиться раньше вывода функции pretty-printing, вызванной до неё. Например,
    Stdlib.print_string "<";
    Format.print_string "PRETTY";
    Stdlib.print_string ">";
    Format.print_string "TEXT";
   
приводит к выводу <>PRETTYTEXT.

Форматтеры

type formatter 

Абстрактные данные, соответствующие средству pretty-printing (также называемому форматтером) и всем связанным с ним механизмам. См. также Определение форматтеров.

Блоки pretty-printing

Механизм pretty-printing использует понятия блока pretty-printing и подсказки переноса для управления отступами и переносами строк.

Для каждого типа блока pretty-printing предусмотрена своя политика разбиения строк:

  • в горизонтальном блоке подсказки переноса никогда не разбивают строку (но строка может быть разбита во вложенном блоке более глубокого уровня);
  • в вертикальном блоке подсказки переноса всегда разбивают строку;
  • в горизонтальном/вертикальном блоке, если блок помещается в текущую строку, подсказки переноса не разбивают строку; в противном случае каждая подсказка переноса разбивает строку;
  • в компактном блоке подсказка переноса не разбивает строку, если только в текущей строке не осталось места.

Обратите внимание, что политика разбиения строк зависит от типа блока: политика блока не определяет политику вложенных блоков. Например, если вертикальный блок вложен в горизонтальный, все подсказки переноса внутри вертикального блока будут разбивать строку.

Кроме того, открытие блока после ограничения максимального отступа приводит к разбиению строки независимо от того, поместился бы блок в строку или нет.

val pp_open_box : formatter -> int -> unit
val open_box : int -> unit

pp_open_box ppf d открывает новый компактный блок pretty-printing со смещением d в форматтере ppf.

В этом блоке средство pretty-printing выводит в каждой строке как можно больше содержимого.

Подсказка переноса разбивает строку, если в ней не осталось места для вывода оставшейся части блока.

В этом блоке средство pretty-printing учитывает структуру блоков: если структурный блок не помещается целиком в простую строку, подсказка переноса также разбивает строку, если это разделение «сдвигает влево» (то есть отступ новой строки меньше отступа текущей строки).

Этот блок предназначен для общего использования в pretty-printing.

Если средство pretty-printing разбивает строку в блоке, к текущему отступу добавляется смещение d.

val pp_close_box : formatter -> unit -> unit
val close_box : unit -> unit

Закрывает последний открытый блок pretty-printing.

val pp_open_hbox : formatter -> unit -> unit
val open_hbox : unit -> unit

pp_open_hbox ppf () открывает новый «горизонтальный» блок pretty-printing.

Этот блок выводит содержимое в одной строке.

Подсказки переноса в горизонтальном блоке никогда не разбивают строку. (Разбиение строк всё ещё может происходить внутри вложенных блоков более глубокого уровня.)

val pp_open_vbox : formatter -> int -> unit
val open_vbox : int -> unit

pp_open_vbox ppf d открывает новый «вертикальный» блок pretty-printing со смещением d.

Этот блок выводит содержимое в нескольких строках, число которых определяется подсказками переноса в блоке.

Каждая подсказка переноса в вертикальном блоке разбивает строку.

Если средство pretty-printing разбивает строку в блоке, к текущему отступу добавляется d.

val pp_open_hvbox : formatter -> int -> unit
val open_hvbox : int -> unit

pp_open_hvbox ppf d открывает новый «горизонтальный/вертикальный» блок pretty-printing со смещением d.

Если этот блок помещается в одну строку, он ведёт себя как горизонтальный блок; в противном случае — как вертикальный.

Если средство pretty-printing разбивает строку в блоке, к текущему отступу добавляется d.

val pp_open_hovbox : formatter -> int -> unit
val open_hovbox : int -> unit

pp_open_hovbox ppf d открывает новый блок pretty-printing типа «горизонтальный или вертикальный» со смещением d.

Этот блок выводит в каждой строке как можно больше содержимого.

Подсказка переноса разбивает строку, если в ней не осталось места для вывода оставшейся части блока.

Если средство pretty-printing разбивает строку в блоке, к текущему отступу добавляется d.

Функции форматирования

val pp_print_string : formatter -> string -> unit
val print_string : string -> unit

pp_print_string ppf s выводит s в текущем блоке pretty-printing.

val pp_print_substring : pos:int -> len:int -> formatter -> string -> unit
val print_substring : pos:int -> len:int -> string -> unit

pp_print_substring ~pos ~len ppf s выводит подстроку s, начинающуюся с позиции pos и заканчивающуюся на позиции pos+len, в текущем блоке pretty-printing.

  • Начиная с версии 5.3
val pp_print_bytes : formatter -> bytes -> unit
val print_bytes : bytes -> unit

pp_print_bytes ppf b выводит b в текущем блоке pretty-printing.

  • Начиная с версии 4.13
val pp_print_as : formatter -> int -> string -> unit
val print_as : int -> string -> unit

pp_print_as ppf len s выводит s в текущем блоке pretty-printing. Средство pretty-printing форматирует s так, как если бы его длина составляла len.

val pp_print_substring_as : pos:int -> len:int -> formatter -> int -> string -> unit
val print_substring_as : pos:int -> len:int -> int -> string -> unit

pp_print_substring_as ~first ~len ppf len_as s выводит подстроку s, начинающуюся с позиции pos и заканчивающуюся на позиции pos+len, в текущем блоке pretty-printing так, как если бы её длина составляла len_as.

  • Начиная с версии 5.1
val pp_print_int : formatter -> int -> unit
val print_int : int -> unit

Выводит целое число в текущем блоке pretty-printing.

val pp_print_float : formatter -> float -> unit
val print_float : float -> unit

Выводит число с плавающей точкой в текущем блоке pretty-printing.

val pp_print_char : formatter -> char -> unit
val print_char : char -> unit

Выводит символ в текущем блоке pretty-printing.

val pp_print_bool : formatter -> bool -> unit
val print_bool : bool -> unit

Выводит логическое значение в текущем блоке pretty-printing.

val pp_print_nothing : formatter -> unit -> unit

Ничего не выводит.

  • Начиная с версии 5.2

Подсказки переноса

«Подсказка переноса» указывает средству pretty-printing вывести пробел или разбить строку — в зависимости от того, что лучше соответствует правилам разбиения текущего блока pretty-printing.

Подсказки переноса используются для разделения выводимых элементов и необходимы, чтобы средство pretty-printing могло корректно разбивать строки и задавать отступы для элементов.

Простые подсказки переноса:

  • «пробел»: вывести пробел или разбить строку, если это уместно;
  • «срез»: разбить строку, если это уместно.

Примечание: понятия пробела и разбиения строки для механизма pretty-printing абстрактны, поскольку программист может полностью переопределить их. Однако в настройках средства pretty-printing по умолчанию «вывести пробел» означает просто вывести символ пробела (код ASCII 32), а «разбить строку» — вывести символ новой строки (код ASCII 10).

val pp_print_space : formatter -> unit -> unit
val print_space : unit -> unit

pp_print_space ppf () создаёт подсказку переноса типа «пробел»: средство pretty-printing может разбить строку в этой точке, а иначе выводит один пробел.

pp_print_space ppf () эквивалентно pp_print_break ppf 1 0.

val pp_print_cut : formatter -> unit -> unit
val print_cut : unit -> unit

pp_print_cut ppf () создаёт подсказку переноса типа «срез»: средство pretty-printing может разбить строку в этой точке, а иначе ничего не выводит.

pp_print_cut ppf () эквивалентно pp_print_break ppf 0 0.

val pp_print_break : formatter -> int -> int -> unit
val print_break : int -> int -> unit

pp_print_break ppf nspaces offset создаёт подсказку переноса типа «полный»: средство pretty-printing может разбить строку в этой точке, а иначе выводит nspaces пробелов.

Если средство pretty-printing разбивает строку, к текущему отступу добавляется offset.

val pp_print_custom_break : formatter ->       fits:string * int * string -> breaks:string * int * string -> unit

pp_print_custom_break ppf ~fits:(s1, n, s2) ~breaks:(s3, m, s4) создаёт пользовательскую подсказку переноса: средство pretty-printing может разбить строку в этой точке.

Если строка не разбивается, выводится s1, затем n пробелов, а затем s2.

Если строка разбивается, выводится строка s3, затем отступ (согласно правилам блока), затем смещение в m пробелов, а затем строка s4.

В то время как n и m обрабатываются функцией formatter_out_functions.out_indent, строки обрабатываются функцией formatter_out_functions.out_string. Это позволяет создать пользовательский форматтер, который особым образом обрабатывает отступы, например выводит теги <br/> или сущности &nbsp;.

Пользовательский перенос полезен, если нужно изменить видимые (не являющиеся пробельными) символы, выводимые при переносе или без него. Например, при выводе списка  [a; b; c]  может потребоваться добавить завершающую точку с запятой, если он выводится вертикально:

[
  a;
  b;
  c;
]
   

Это можно сделать следующим образом:

printf "@[<v 0>[@;<0 2>@[<v 0>a;@,b;@,c@]%t]@]@\n"
  (pp_print_custom_break ~fits:("", 0, "") ~breaks:(";", 0, ""))
   
  • Начиная с версии 4.08
val pp_force_newline : formatter -> unit -> unit
val force_newline : unit -> unit

Принудительно переводит строку в текущем блоке pretty-printing.

Средство pretty-printing обязано разбить строку в этой точке.

Это не обычный способ использования pretty-printing, поскольку императивное разбиение строк может помешать работе текущих счётчиков строк и вычислению размера блока. Лучше использовать подсказки переноса внутри охватывающего вертикального блока.

val pp_print_if_newline : formatter -> unit -> unit
val print_if_newline : unit -> unit

Выполняет следующую команду форматирования, если предшествующая строка только что была разбита. В противном случае следующая команда форматирования игнорируется.

Завершение pretty-printing

val pp_print_flush : formatter -> unit -> unit
val print_flush : unit -> unit

Завершает pretty-printing и сбрасывает средство pretty-printing в исходное состояние.

Все открытые блоки pretty-printing закрываются, весь ожидающий текст выводится. Кроме того, выполняется сброс низкоуровневого устройства вывода средства pretty-printing, чтобы гарантировать фактическое отображение всего ожидающего текста.

Примечание: не используйте print_flush при обычной работе процедуры pretty-printing, поскольку средство pretty-printing использует сложный механизм буферизации для корректного задания отступов. Произвольный ручной сброс этих буферов нарушит работу механизма pretty-printing и приведёт к некачественному отображению.

Используйте print_flush только тогда, когда необходимо отобразить всё ожидающее содержимое (например, при интерактивном использовании, когда нужно, чтобы пользователь прочитал текст) и сброс состояния средства pretty-printing не помешает дальнейшему форматированию.

Предупреждение: если устройство вывода средства pretty-printing — канал вывода, повторные вызовы print_flush означают повторные вызовы flush для сброса канала вывода; такие явные вызовы сброса могут нарушить стратегию буферизации каналов вывода и существенно снизить производительность.

val pp_print_newline : formatter -> unit -> unit
val print_newline : unit -> unit

Завершает pretty-printing и сбрасывает средство pretty-printing в исходное состояние.

Все открытые блоки pretty-printing закрываются, весь ожидающий текст выводится.

Эквивалентно Format.print_flush, но непосредственно перед сбросом низкоуровневого устройства вывода средства pretty-printing в него выводится символ новой строки. См. соответствующие предупреждения для Format.print_flush.

Примечание: это не обычный способ вывода новой строки; предпочтительнее использовать подсказки переноса внутри вертикального блока pretty-printing.

Ширина поля

val pp_infinity : int

pp_infinity — максимальный размер поля. Его точное значение зависит от реализации, но гарантированно превышает 109.

  • Начиная с версии 5.2
val pp_set_margin : formatter -> int -> unit
val set_margin : int -> unit

pp_set_margin ppf d задаёт ширину поля справа, равную d (в символах): средство pretty-printing разбивает строки, выходящие за правую границу поля, в соответствии с заданными подсказками переноса. Задание ширины поля d означает, что механизм форматирования стремится выводить не более d-1 символов в строке. Ничего не происходит, если d меньше 2. Если d >= Format.pp_infinity, правая граница поля задаётся равной Format.pp_infinity - 1. Если d меньше текущего ограничения максимального отступа, ограничение максимального отступа уменьшается с попыткой сохранить минимальное отношение max_indent/margin>=50% и, если возможно, текущую разницу margin - max_indent.

См. также Format.pp_set_geometry.

val pp_get_margin : formatter -> unit -> int
val get_margin : unit -> int

Возвращает положение правой границы поля.

Ограничение максимального отступа

val pp_set_max_indent : formatter -> int -> unit
val set_max_indent : int -> unit

pp_set_max_indent ppf d задаёт ограничение максимального отступа строк, равное d (в символах): после достижения этого ограничения новые блоки pretty-printing сдвигаются влево, если только охватывающий блок не помещается целиком в текущую строку. Например,

 set_margin 10; set_max_indent 5; printf "@[123456@[7@]89A@]@." 

даёт следующий результат:

    123456
    789A
  

поскольку вложенный блок "@[7@]" открывается после ограничения максимального отступа (7>5), а его родительский блок не помещается в текущую строку. Можно либо уменьшить длину родительского блока, чтобы он поместился в строку:

 printf "@[123456@[7@]89@]@." 

либо открыть промежуточный блок до достижения ограничения максимального отступа, который помещается в текущую строку,

 printf "@[123@[456@[7@]89@]A@]@." 

чтобы избежать сдвига вложенных блоков влево и вывести соответственно "123456789" и "123456789A". Обратите также внимание, что вертикальные блоки никогда не помещаются в строку, тогда как горизонтальные блоки всегда помещаются в текущую строку целиком. Открытие блока может разбить строку, даже если его содержимое в неё помещалось бы. Если такое поведение нежелательно, его можно ограничить, задав ограничение максимального отступа равным margin - 1. Обратите внимание, что задавать ограничение максимального отступа равным margin нельзя.

Ничего не происходит, если d меньше 2.

Если d больше текущей ширины поля, значение игнорируется, а текущее ограничение максимального отступа сохраняется.

См. также Format.pp_set_geometry.

val pp_get_max_indent : formatter -> unit -> int
val get_max_indent : unit -> int

Возвращает ограничение максимального отступа (в символах).

Геометрия

Геометрические функции позволяют одновременно изменять связанные переменные: ширину поля и ограничение максимального отступа.

type geometry = {
max_indent : int;
margin : int;
}
  • Начиная с версии 4.08
val check_geometry : geometry -> bool

Проверяет корректность геометрии форматтера: 1 < max_indent < margin < Format.pp_infinity

  • Начиная с версии 4.08
val pp_set_geometry : formatter -> max_indent:int -> margin:int -> unit
val set_geometry : max_indent:int -> margin:int -> unit
val pp_safe_set_geometry : formatter -> max_indent:int -> margin:int -> unit
val safe_set_geometry : max_indent:int -> margin:int -> unit

pp_set_geometry ppf ~max_indent ~margin задаёт ширину поля и ограничение максимального отступа для ppf.

Если 1 < max_indent < margin < Format.pp_infinity, pp_set_geometry ppf ~max_indent ~margin эквивалентно pp_set_margin ppf margin; pp_set_max_indent ppf max_indent и позволяет избежать слегка некорректного поведения pp_set_max_indent ppf max_indent; pp_set_margin ppf margin.

За пределами этой области pp_set_geometry вызывает исключение недопустимого аргумента, тогда как pp_safe_set_geometry ничего не делает.

  • Начиная с версии 4.08
val pp_update_geometry : formatter -> (geometry -> geometry) -> unit

pp_update_geometry ppf (fun geo -> { geo with ... }) позволяет обновлять геометрию форматтера так, чтобы это не нарушало работу при добавлении новых полей в запись geometry.

Вызывает исключение недопустимого аргумента, если возвращённая геометрия не удовлетворяет условию Format.check_geometry.

  • Начиная с версии 4.11
val update_geometry : (geometry -> geometry) -> unit
val pp_get_geometry : formatter -> unit -> geometry
val get_geometry : unit -> geometry

Возвращает текущую геометрию форматтера.

  • Начиная с версии 4.08

Максимальная глубина форматирования

Максимальная глубина форматирования — это максимальное количество одновременно открытых блоков pretty-printing.

Содержимое блоков, вложенных глубже, выводится как многоточие (точнее, как текст, возвращаемый функцией Format.get_ellipsis_text ()).

val pp_set_max_boxes : formatter -> int -> unit
val set_max_boxes : int -> unit

pp_set_max_boxes ppf max задаёт максимальное количество одновременно открытых блоков pretty-printing.

Содержимое блоков, вложенных глубже, выводится как многоточие (точнее, как текст, возвращаемый функцией Format.get_ellipsis_text ()).

Ничего не происходит, если max меньше 2.

val pp_get_max_boxes : formatter -> unit -> int
val get_max_boxes : unit -> int

Возвращает максимальное количество блоков pretty-printing, которые можно открыть до появления многоточия.

val pp_over_max_boxes : formatter -> unit -> bool
val over_max_boxes : unit -> bool

Проверяет, открыто ли уже максимально допустимое количество блоков pretty-printing.

Табуляционные блоки

Табуляционный блок выводит содержимое в строках, разделённых на ячейки фиксированной ширины. Табуляционный блок позволяет просто отображать вертикальные столбцы текста, выровненного по левому краю.

В этом блоке предусмотрена команда set_tab для определения границ ячеек и команда print_tab для перехода от ячейки к ячейке и разбиения строки, когда в ней больше не остаётся ячеек для вывода.

Примечание: вывод в табуляционном блоке выполняется построчно, поэтому произвольное разбиение строк внутри такого блока приводит к некачественному отображению. Тем не менее контролируемое использование табуляционных блоков позволяет просто выводить столбцы с помощью модуля Format.

val pp_open_tbox : formatter -> unit -> unit
val open_tbox : unit -> unit

open_tbox () открывает новый табуляционный блок.

Этот блок выводит строки, разделённые на ячейки фиксированной ширины.

Внутри табуляционного блока специальные маркеры табуляции задают важные позиции в строке (например, границы ячеек). Функция Format.set_tab устанавливает маркер табуляции в точке вставки.

В табуляционном блоке предусмотрены специальные табуляционные переносы для перехода к следующему маркеру табуляции или разбиения строки. Функция Format.print_tbreak выводит табуляционный перенос.

val pp_close_tbox : formatter -> unit -> unit
val close_tbox : unit -> unit

Закрывает последний открытый табуляционный блок.

val pp_set_tab : formatter -> unit -> unit
val set_tab : unit -> unit

Устанавливает маркер табуляции в текущей точке вставки.

val pp_print_tab : formatter -> unit -> unit
val print_tab : unit -> unit

print_tab () создаёт подсказку табуляционного переноса типа «следующий»: если точка вставки ещё не находится на маркере табуляции, она перемещается к первому маркеру табуляции справа; если такого маркера нет, средство pretty-printing разбивает строку, а точка вставки перемещается к крайнему левому маркеру табуляции.

Эквивалентно print_tbreak 0 0.

val pp_print_tbreak : formatter -> int -> int -> unit
val print_tbreak : int -> int -> unit

print_tbreak nspaces offset создаёт подсказку табуляционного переноса типа «полный».

Если точка вставки ещё не находится на маркере табуляции, она перемещается к первому маркеру табуляции справа, а средство pretty-printing выводит nspaces пробелов.

Если справа нет следующего маркера табуляции, средство pretty-printing разбивает строку в этой точке, после чего точка вставки перемещается к крайнему левому маркеру табуляции блока.

Если средство pretty-printing разбивает строку, к текущему отступу добавляется offset.

Многоточие

val pp_set_ellipsis_text : formatter -> string -> unit
val set_ellipsis_text : string -> unit

Задаёт текст многоточия, выводимого при слишком большом количестве открытых блоков pretty-printing (по умолчанию — одна точка, .).

val pp_get_ellipsis_text : formatter -> unit -> string
val get_ellipsis_text : unit -> string

Возвращает текст многоточия.

Семантические теги

type stag = ..

Семантические теги (или просто теги) — это пользовательские аннотации, связывающие специфические для пользователя операции с выводимыми сущностями.

Обычно семантические теги используются для оформления текста: например, для отображения заданного шрифта или размера текста на устройстве вывода либо для обозначения границ сущностей (например, элементов HTML или TeX либо управляющих последовательностей терминала). Более сложные варианты использования семантических тегов позволяют динамически изменять поведение модуля форматирования для корректного вывода содержимого определённых тегов. Например, можно определить тег RGB следующим образом:

type stag += RGB of {r:int;g:int;b:int}

Чтобы корректно ограничить выводимые сущности, семантический тег необходимо открыть перед сущностью и закрыть после неё. Семантические теги должны быть правильно вложены, как скобки, с помощью Format.pp_open_stag и Format.pp_close_stag.

Специфические для тегов операции выполняются при каждом открытии или закрытии тега. При каждом таком событии выполняются два вида операций: маркировка тега и вывод тега:

  • Маркировка тега — более простая специфическая для тега операция: она просто записывает специфическую для тега строку в устройство вывода модуля форматирования. Маркировка тегов не влияет на вычисление разбиения строк.
  • Вывод тега — более сложная специфическая для тега операция: она может выводить произвольное содержимое в модуль форматирования. Вывод тегов тесно связан с текущими операциями модуля красивой печати.

В целом маркировка тегов обычно используется для более качественного отображения текста на устройстве вывода, а вывод тегов позволяет точно настраивать процедуры печати, чтобы выводить одну и ту же сущность по-разному в зависимости от семантических тегов (то есть добавлять дополнительное содержимое или даже опускать части вывода).

Точнее: при открытии или закрытии семантического тега последовательно выполняются обе операции — «вывод тега» и «маркировка тега»:

  • Вывод семантического тега означает вызов специфической для модуля форматирования функции print_open_stag (соответственно, print_close_stag) с именем тега в качестве аргумента: эта функция вывода тега может вывести в модуль форматирования любое обычное содержимое (которое, как обычно, ставится в очередь модуля форматирования для последующего вычисления разбиения строк).
  • Маркировка семантического тега означает вызов специфической для модуля форматирования функции mark_open_stag (соответственно, mark_close_stag) с именем тега в качестве аргумента: эта функция маркировки тега может вернуть «маркер открытия тега» (соответственно, «маркер закрытия тега») для непосредственного вывода в устройство вывода модуля форматирования.

Поскольку строки-маркеры семантических тегов записываются непосредственно в устройство вывода модуля форматирования, они не считаются частью печатаемого содержимого, влияющего на разбиение строк (иначе говоря, длина строк, соответствующих маркерам тегов, считается равной нулю при разбиении строк).

Таким образом, обработка семантических тегов в некотором смысле прозрачна для красивой печати и не влияет на обычные отступы. Поэтому одна процедура красивой печати может выводить как простое «буквальное» содержимое, так и более сложное оформленное содержимое — в зависимости от обработки тегов. По умолчанию теги неактивны, поэтому вывод не оформляется информацией о тегах. Если установить set_tags в true, механизм красивой печати будет учитывать теги и соответственно оформлять вывод.

Функции маркировки тегов по умолчанию ведут себя как в HTML: строковые теги заключаются в «<» и «>», тогда как остальные теги игнорируются; поэтому маркером открытия для строкового тега "t" является "<t>", а маркером закрытия — "</t>".

Функции вывода тегов по умолчанию ничего не делают.

Функции маркировки и вывода тегов можно определить самостоятельно и задать вызовом Format.set_formatter_stag_functions.

Обработку семантических тегов можно включить или выключить с помощью Format.set_tags. Операции маркировки тегов можно включить или выключить с помощью Format.set_mark_tags. Операции вывода тегов можно включить или выключить с помощью Format.set_print_tags.

  • С версии 4.08
type tag = string 
type stag += 
| String_tag of tag (*

String_tag s — это строковый тег s. Строковые теги можно вставить либо явно с помощью конструктора String_tag, либо с помощью специального синтаксиса формата "@{<s> ... @}".

  • С версии 4.08
*)
val pp_open_stag : formatter -> stag -> unit
val open_stag : stag -> unit

pp_open_stag ppf t открывает семантический тег с именем t.

Вызывается функция вывода тегов print_open_stag модуля форматирования, которой передаётся аргумент t; затем маркер открытия тега для t, заданный функцией mark_open_stag t, записывается в устройство вывода модуля форматирования.

  • С версии 4.08
val pp_close_stag : formatter -> unit -> unit
val close_stag : unit -> unit

pp_close_stag ppf () закрывает последний открытый семантический тег t.

Маркер закрытия тега, заданный функцией mark_close_stag t, записывается в устройство вывода модуля форматирования; затем вызывается функция вывода тегов print_close_stag модуля форматирования, которой передаётся аргумент t.

  • С версии 4.08
val pp_set_tags : formatter -> bool -> unit
val set_tags : bool -> unit

pp_set_tags ppf b включает или выключает обработку семантических тегов (по умолчанию выключена).

val pp_set_print_tags : formatter -> bool -> unit
val set_print_tags : bool -> unit

pp_set_print_tags ppf b включает или выключает операции вывода тегов.

val pp_set_mark_tags : formatter -> bool -> unit
val set_mark_tags : bool -> unit

pp_set_mark_tags ppf b включает или выключает операции маркировки тегов.

val pp_get_print_tags : formatter -> unit -> bool
val get_print_tags : unit -> bool

Возвращает текущее состояние операций вывода тегов.

val pp_get_mark_tags : formatter -> unit -> bool
val get_mark_tags : unit -> bool

Возвращает текущее состояние операций маркировки тегов.

val pp_set_formatter_out_channel : formatter -> out_channel -> unit

Перенаправление стандартного вывода модуля форматирования

val set_formatter_out_channel : out_channel -> unit

Перенаправляет стандартный вывод модуля красивой печати в указанный канал. (Все функции вывода стандартного модуля форматирования заменяются функциями вывода по умолчанию, которые печатают в указанный канал.)

set_formatter_out_channel эквивалентно Format.pp_set_formatter_out_channel std_formatter.

val pp_set_formatter_output_functions : formatter -> (string -> int -> int -> unit) -> (unit -> unit) -> unit
val set_formatter_output_functions : (string -> int -> int -> unit) -> (unit -> unit) -> unit

pp_set_formatter_output_functions ppf out flush перенаправляет функции вывода стандартного модуля красивой печати на функции out и flush.

Функция out выполняет весь строковый вывод модуля красивой печати. Она вызывается со строкой s, начальной позицией p и числом символов n; предполагается, что она выводит символы с p по p + n - 1 строки s.

Функция flush вызывается при каждом сбросе модуля красивой печати (посредством преобразования %!, указаний красивой печати @? или @. либо низкоуровневых функций print_flush или print_newline).

val pp_get_formatter_output_functions : formatter -> unit -> (string -> int -> int -> unit) * (unit -> unit)
val get_formatter_output_functions : unit -> (string -> int -> int -> unit) * (unit -> unit)

Возвращает текущие функции вывода стандартного модуля красивой печати.

Переопределение вывода модуля форматирования

Модуль Format достаточно гибок, чтобы позволить полностью переопределить смысл вывода красивой печати: можно предоставить собственные функции, определяющие обработку отступов, разбиение строк и даже вывод всех символов!

Переопределение функций вывода

type formatter_out_functions = {
out_string : string -> int -> int -> unit;
out_width : string -> pos:int -> len:int -> int; (*
  • С версии 5.4
*)
out_flush : unit -> unit;
out_newline : unit -> unit;
out_spaces : int -> unit;
out_indent : int -> unit; (*
  • С версии 4.06
*)
}

Набор функций вывода, специфичных для модуля форматирования:

  • функция out_string выполняет весь строковый вывод модуля красивой печати. Она вызывается со строкой s, начальной позицией p и числом символов n; предполагается, что она выводит символы с p по p + n - 1 строки s.
  • функция out_width сообщает механизму форматирования ширину подстроки в том виде, в каком она отображается на устройстве вывода. Явная информация о ширине, заданная с помощью @<n>, Format.pp_print_as или Format.pp_print_substring_as, имеет приоритет над этой функцией. Кроме того, механизм форматирования вычисляет ширину строковых аргументов Format.pp_print_string и аргументов-подстрок Format.pp_print_substring целиком. Следовательно, out_width можно использовать для вычисления приблизительной ширины подстрок в Unicode.
  • функция out_flush сбрасывает устройство вывода модуля красивой печати.
  • out_newline вызывается для открытия новой строки при её разбиении модулем красивой печати.
  • функция out_spaces выводит пробелы, когда подсказка переноса приводит к вставке пробелов вместо разбиения строки. Ей передаётся количество пробелов для вывода.
  • функция out_indent выполняет отступ новой строки при её разбиении модулем красивой печати. Ей передаётся значение отступа новой строки.

По умолчанию:

  • поля out_string и out_flush зависят от устройства вывода (например, output_string и flush для устройства типа out_channel либо Buffer.add_substring и ignore для устройства вывода типа Buffer.t),
  • поле out_width — это количество скалярных значений Unicode (см. Format.utf_8_scalar_width) в подстроке.
  • поле out_newline эквивалентно out_string "\n" 0 1;
  • поля out_spaces и out_indent эквивалентны out_string (String.make n ' ') 0 n.
  • С версии 4.01
val pp_set_formatter_out_functions : formatter -> formatter_out_functions -> unit
val set_formatter_out_functions : formatter_out_functions -> unit

pp_set_formatter_out_functions ppf out_funs Устанавливает для всех функций вывода модуля красивой печати ppf значения, заданные аргументом out_funs.

Это позволяет изменить смысл отступов (которые могут означать нечто иное, чем просто вывод пробелов) и открытия новых строк (которое может быть связано с любым другим действием, необходимым конкретному приложению).

Разумными значениями по умолчанию для функций out_spaces, out_newline и out_width являются соответственно out_funs.out_string (String.make n ' ') 0 n, out_funs.out_string "\n" 0 1 и Format.utf_8_scalar_width.

  • С версии 4.01
val pp_get_formatter_out_functions : formatter -> unit -> formatter_out_functions
val get_formatter_out_functions : unit -> formatter_out_functions

Возвращает текущие функции вывода модуля красивой печати, включая функции разбиения строк и отступов. Полезно для сохранения текущих настроек и их последующего восстановления.

  • С версии 4.01
val utf_8_scalar_width : string -> pos:int -> len:int -> int

utf_8_scalar_width s ~pos ~len — это количество скалярных значений Unicode в подстроке String.sub s pos len. Некорректные последовательности байтов неявно заменяются на U+FFFD, поскольку это обеспечивает более точную оценку ширины для других схем кодирования на основе ASCII, например ISO-8859-15. Эта функция out_width используется по умолчанию начиная с OCaml 5.4.

  • С версии 5.4
val ascii_width : string -> pos:int -> len:int -> int

ascii_width s ~pos ~len — это len.

  • С версии 5.4

Переопределение операций с семантическими тегами

type formatter_stag_functions = {
mark_open_stag : stag -> string;
mark_close_stag : stag -> string;
print_open_stag : stag -> unit;
print_close_stag : stag -> unit;
}

Функции обработки семантических тегов, специфичные для модуля форматирования: варианты mark — это функции «маркировки тегов», связывающие строковый маркер с тегом, чтобы механизм красивой печати мог записывать эти маркеры в устройство вывода модуля форматирования в виде токенов нулевой длины. Варианты print — это функции «вывода тегов», которые могут выполнять обычную печать при открытии или закрытии тега.

  • С версии 4.08
val pp_set_formatter_stag_functions : formatter -> formatter_stag_functions -> unit
val set_formatter_stag_functions : formatter_stag_functions -> unit

pp_set_formatter_stag_functions ppf tag_funs изменяет обработку операций открытия и закрытия семантических тегов, чтобы при печати в ppf использовать функции из tag_funs.

При открытии семантического тега с именем t строка t передаётся функции маркировки открытия тега (полю mark_open_stag записи tag_funs), которая должна вернуть маркер открытия тега для этого имени. При следующем вызове close_stag () имя семантического тега t передаётся функции маркировки закрытия тега (полю mark_close_stag записи tag_funs), которая должна вернуть маркер закрытия тега для этого имени.

Поле print_ записи содержит функции вывода тегов, вызываемые при открытии и закрытии тега для вывода обычного содержимого в очередь модуля красивой печати.

  • С версии 4.08
val pp_get_formatter_stag_functions : formatter -> unit -> formatter_stag_functions
val get_formatter_stag_functions : unit -> formatter_stag_functions

Возвращает текущие функции обработки семантических тегов стандартного модуля красивой печати.

  • С версии 4.08

Определение модулей форматирования

Определение новых модулей форматирования позволяет параллельно выводить независимое содержимое на несколько устройств вывода. Все параметры модуля форматирования локальны для него: правое поле, максимальное ограничение отступа, максимальное количество одновременно открытых блоков красивой печати, многоточие и так далее — задаются отдельно для каждого модуля форматирования.

Например, если имеется буфер Buffer.t b, функция Format.formatter_of_buffer b возвращает новый модуль форматирования, использующий буфер b в качестве устройства вывода. Аналогично, если имеется выходной канал out_channel oc, функция Format.formatter_of_out_channel oc возвращает новый модуль форматирования, использующий канал oc в качестве устройства вывода.

Кроме того, если имеется out_funs — полный набор функций вывода для модуля форматирования, — функция Format.formatter_of_out_functions out_funs создаёт новый модуль форматирования, использующий эти функции для вывода.

val formatter_of_out_channel : out_channel -> formatter

formatter_of_out_channel oc возвращает новый модуль форматирования, выполняющий запись в соответствующий выходной канал oc.

val synchronized_formatter_of_out_channel : out_channel -> formatter Domain.DLS.key

synchronized_formatter_of_out_channel oc возвращает ключ локального для домена состояния, содержащего модуль форматирования, локальный для домена и предназначенный для записи в соответствующий выходной канал oc.

Если модуль форматирования используется несколькими доменами, вывод из этих доменов будет перемежаться в точках сброса модуля форматирования, например при вызове Format.print_flush.

  • Предупреждение: нестабильный API.
val std_formatter : formatter

Стандартный модуль форматирования начального домена для вывода в стандартный поток вывода.

Он определён как Format.formatter_of_out_channel stdout.

val get_std_formatter : unit -> formatter

get_std_formatter () возвращает стандартный модуль форматирования текущего домена, используемый для вывода в стандартный поток вывода.

  • С версии 5.0
val err_formatter : formatter

Модуль форматирования начального домена для вывода в стандартный поток ошибок.

Он определён как Format.formatter_of_out_channel stderr.

val get_err_formatter : unit -> formatter

get_err_formatter () возвращает модуль форматирования текущего домена, используемый для вывода в стандартный поток ошибок.

  • С версии 5.0
val formatter_of_buffer : Buffer.t -> formatter

formatter_of_buffer b возвращает новый модуль форматирования, выполняющий запись в буфер b. По завершении красивой печати необходимо сбросить модуль форматирования с помощью Format.pp_print_flush или Format.pp_print_newline, чтобы вывести всё ожидающее содержимое в буфер.

val stdbuf : Buffer.t

Строковый буфер начального домена, в который выполняет запись str_formatter.

val get_stdbuf : unit -> Buffer.t

get_stdbuf () возвращает строковый буфер текущего домена, в который выполняет запись строковый модуль форматирования текущего домена.

  • С версии 5.0
val str_formatter : formatter

Модуль форматирования начального домена для вывода в строковый буфер Format.stdbuf.

str_formatter определён как Format.formatter_of_buffer Format.stdbuf.

val get_str_formatter : unit -> formatter

Модуль форматирования текущего домена для вывода в строковый буфер текущего домена.

  • С версии 5.0
val flush_str_formatter : unit -> string

Возвращает содержимое, напечатанное с помощью str_formatter текущего домена, сбрасывает модуль форматирования и очищает соответствующий буфер.

val make_formatter : (string -> int -> int -> unit) -> (unit -> unit) -> formatter

make_formatter out flush возвращает новый модуль форматирования, выполняющий вывод с помощью функции out и сброс с помощью функции flush.

Например,

    make_formatter
      (Stdlib.output_substring oc)
      (fun () -> Stdlib.flush oc)
  

возвращает модуль форматирования для out_channel oc.

val make_synchronized_formatter : (string -> int -> int -> unit) ->       (unit -> unit) -> formatter Domain.DLS.key

make_synchronized_formatter out flush возвращает ключ локального для домена состояния, содержащего модуль форматирования, локальный для домена, который выполняет вывод с помощью функции out и сброс с помощью функции flush.

Если модуль форматирования используется несколькими доменами, вывод из этих доменов будет перемежаться в точках сброса модуля форматирования, например при вызове Format.print_flush.

  • С версии 5.0
  • Предупреждение: нестабильный API.
val formatter_of_out_functions : formatter_out_functions -> formatter

formatter_of_out_functions out_funs возвращает новый модуль форматирования, который выполняет запись с помощью набора функций вывода out_funs.

Значение аргумента out_funs см. в определении типа Format.formatter_out_functions.

  • С версии 4.06

Символическая красивая печать

Символическая красивая печать — это красивая печать с использованием символического модуля форматирования, то есть модуля форматирования, который выводит символические элементы красивой печати.

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

На практике сначала определите буфер символического вывода b с помощью:

  • let sob = make_symbolic_output_buffer (). Затем определите символический модуль форматирования с помощью:
  • let ppf = formatter_of_symbolic_output_buffer sob

Используйте символический модуль форматирования ppf как обычно, а по завершении красивой печати извлеките символические элементы, сбросив буфер символического вывода sob с помощью:

  • flush_symbolic_output_buffer sob.
type symbolic_output_item = 
| Output_flush (*

символическая команда сброса

*)
| Output_newline (*

символическая команда перевода строки

*)
| Output_string of string (*

Output_string s: символический вывод строки s

*)
| Output_spaces of int (*

Output_spaces n: символическая команда вывода n пробелов

*)
| Output_indent of int (*

Output_indent i: символический отступ размером i

*)

Элементы, создаваемые модулями символической красивой печати

  • С версии 4.06
type symbolic_output_buffer 

Буфер вывода символического модуля красивой печати.

  • С версии 4.06
val make_symbolic_output_buffer : unit -> symbolic_output_buffer

make_symbolic_output_buffer () возвращает новый буфер для символического вывода.

  • С версии 4.06
val clear_symbolic_output_buffer : symbolic_output_buffer -> unit

clear_symbolic_output_buffer sob очищает буфер sob.

  • С версии 4.06
val get_symbolic_output_buffer : symbolic_output_buffer -> symbolic_output_item list

get_symbolic_output_buffer sob возвращает содержимое буфера sob.

  • С версии 4.06
val flush_symbolic_output_buffer : symbolic_output_buffer -> symbolic_output_item list

flush_symbolic_output_buffer sob возвращает содержимое буфера sob и очищает буфер sob. flush_symbolic_output_buffer sob эквивалентно let items = get_symbolic_output_buffer sob in
   clear_symbolic_output_buffer sob; items

  • С версии 4.06
val add_symbolic_output_item : symbolic_output_buffer -> symbolic_output_item -> unit

add_symbolic_output_item sob itm добавляет элемент itm в буфер sob.

  • С версии 4.06
val formatter_of_symbolic_output_buffer : symbolic_output_buffer -> formatter

formatter_of_symbolic_output_buffer sob возвращает символический модуль форматирования, выполняющий вывод в symbolic_output_buffer sob.

  • С версии 4.06

Вспомогательные функции форматирования.

val pp_print_iter : ?pp_sep:(formatter -> unit -> unit) ->       (('a -> unit) -> 'b -> unit) ->       (formatter -> 'a -> unit) -> formatter -> 'b -> unit

pp_print_iter ~pp_sep iter pp_v ppf v форматирует на ppf итерации iter по коллекции v значений, используя pp_v. Итерации разделяются с помощью pp_sep (по умолчанию — Format.pp_print_cut).

  • С версии 5.1
val pp_print_list : ?pp_sep:(formatter -> unit -> unit) ->       (formatter -> 'a -> unit) -> formatter -> 'a list -> unit

pp_print_list ?pp_sep pp_v ppf l выводит элементы списка l, используя pp_v для вывода каждого элемента и вызывая pp_sep между элементами (по умолчанию pp_sep равно Format.pp_print_cut). Для пустых списков ничего не делает.

  • С версии 4.02
val pp_print_array : ?pp_sep:(formatter -> unit -> unit) ->       (formatter -> 'a -> unit) -> formatter -> 'a array -> unit

pp_print_array ?pp_sep pp_v ppf a выводит элементы массива a, используя pp_v для вывода каждого элемента и вызывая pp_sep между элементами (по умолчанию pp_sep — Format.pp_print_cut). Ничего не делает для пустых массивов.

Если a изменяется после вызова pp_print_array, выведенные значения могут отличаться от ожидаемых, поскольку Format может отложить вывод. Этого можно избежать, сбросив буфер ppf.

  • Начиная с версии 5.1
val pp_print_seq : ?pp_sep:(formatter -> unit -> unit) ->       (formatter -> 'a -> unit) ->       formatter -> 'a Seq.t -> unit

pp_print_seq ?pp_sep pp_v ppf s выводит элементы последовательности s, используя pp_v для вывода каждого элемента и вызывая pp_sep между элементами (по умолчанию pp_sep — Format.pp_print_cut). Ничего не делает для пустых последовательностей.

Эта функция не завершается для бесконечных последовательностей.

  • Начиная с версии 4.12
val pp_print_text : formatter -> string -> unit

pp_print_text ppf s выводит s, используя для пробелов и переводов строк соответственно Format.pp_print_space и Format.pp_force_newline.

  • Начиная с версии 4.02
val format_text : ('a, 'b, 'c, 'd, 'e, 'f) format6 ->       ('a, 'b, 'c, 'd, 'e, 'f) format6

format_text fmt заменяет пробелы и переводы строк в строковом литерале формата fmt на подсказки переноса или принудительные переводы строк:

  • Пустые строки (строки, состоящие только из пробелов (U+0020)) заменяются на "@n".
  • Последовательности пробелов и перевода строки (U+000A), стоящие перед пустой строкой, заменяются на "@n": пустые строки остаются пустыми в выводе.
  • Оставшиеся последовательности из k пробелов и переводов строк заменяются на "@;<0 k'>", где k' = max 1 k не меньше 1.
  • Переносов можно избежать, используя неразрывные пробелы (U+00A0).
  • Принудительный перевод строки можно задать с помощью "@\n"
  • Начиная с версии 5.4
val pp_print_option : ?none:(formatter -> unit -> unit) ->       (formatter -> 'a -> unit) -> formatter -> 'a option -> unit

pp_print_option ?none pp_v ppf o выводит o в ppf, используя pp_v, если o равно Some v, и none, если оно равно None. По умолчанию none ничего не выводит.

  • Начиная с версии 4.08
val pp_print_result : ok:(formatter -> 'a -> unit) ->       error:(formatter -> 'e -> unit) ->       formatter -> ('a, 'e) result -> unit

pp_print_result ~ok ~error ppf r выводит r в ppf, используя ok, если r равно Ok _, и error, если r равно Error _.

  • Начиная с версии 4.08
val pp_print_either : left:(formatter -> 'a -> unit) ->       right:(formatter -> 'b -> unit) ->       formatter -> ('a, 'b) Either.t -> unit

pp_print_either ~left ~right ppf e выводит e в ppf, используя left, если e равно Either.Left _, и right, если e равно Either.Right _.

  • Начиная с версии 4.13

Форматированный красивый вывод

Модуль Format предоставляет полный набор функций, подобных printf, для красивого вывода с использованием спецификаций строк формата.

В строки формата можно добавлять специальные аннотации, задающие команды красивого вывода для механизма форматирования.

Эти аннотации вводятся в строки формата с помощью символа @. Например, @  означает пробел с возможностью переноса, @, означает отсечение, @[ открывает новую рамку, а @] закрывает последнюю открытую рамку.

val fprintf : formatter -> ('a, formatter, unit) format -> 'a

fprintf ff fmt arg1 ... argN форматирует аргументы arg1 в argN согласно строке формата fmt и выводит результирующую строку в форматтер ff.

Строка формата fmt — это символьная строка, содержащая три вида объектов: обычные символы, спецификации преобразования, определённые в модуле Printf, и указания для красивого вывода, специфичные для модуля Format.

Символы указаний для красивого вывода вводятся символом @ и имеют следующие значения:

  • @[: открыть рамку красивого вывода. Тип и смещение рамки можно указать необязательно, используя следующий синтаксис: символ <, за которым следует необязательное обозначение типа рамки, затем необязательное целое смещение и закрывающий символ >. Тип рамки красивого вывода может быть одним из следующих: h, v, hv, b или hov. «h» обозначает «горизонтальную» рамку красивого вывода, «v» — «вертикальную», «hv» — «горизонтально-вертикальную», «b» — «горизонтальную или вертикальную» рамку с отступом, а «hov» — простую «горизонтальную или вертикальную» рамку. Например, @[<hov 2> открывает «горизонтальную или вертикальную» рамку красивого вывода с отступом 2, как это делается с помощью open_hovbox 2. Подробнее о рамках красивого вывода см. описания различных функций открытия рамок open_*box.
  • @]: закрыть последнюю открытую рамку красивого вывода.
  • @,: вывести подсказку переноса «с отсечением», как и print_cut ().
  • @ : вывести подсказку переноса «пробел», как и print_space ().
  • @;: вывести подсказку «полного» переноса, как и print_break. Параметры nspaces и offset подсказки переноса можно указать необязательно, используя следующий синтаксис: символ <, за которым следует целочисленное значение nspaces, затем целое число offset и закрывающий символ >. Если параметры не заданы, полный перенос по умолчанию соответствует подсказке переноса «пробел».
  • @.: сбросить буфер средства красивого вывода и разделить строку, как и print_newline ().
  • @<n>: вывести следующий элемент, как если бы его длина была равна n. Поэтому printf "@<0>%s" arg выводит arg как строку нулевой длины. Если за @<n> не следует спецификация преобразования, следующий символ формата выводится так, как если бы его длина была равна n.
  • @{: открыть семантический тег. Имя тега можно указать необязательно, используя следующий синтаксис: символ <, за которым следует необязательная спецификация строки и закрывающий символ >. Спецификация строки — это любая символьная строка, не содержащая закрывающий символ '>'. Если имя опущено, по умолчанию оно равно пустой строке. Подробнее о семантических тегах см. описания функций Format.open_stag и Format.close_stag.
  • @}: закрыть последний открытый семантический тег.
  • @?: сбросить буфер средства красивого вывода, как и print_flush (). Это эквивалентно преобразованию %!.
  • @\n: принудительно перевести строку, как и force_newline (). Это не обычный способ красивого вывода; предпочтительнее использовать подсказки переноса внутри вертикальной рамки красивого вывода.

Примечание: чтобы символ @ не интерпретировался как указание для красивого вывода, экранируйте его символом %. Старый режим цитирования @@ устарел, поскольку он несовместим с интерпретацией символа '@' при форматированном вводе.

Пример: printf "@[%s@ %d@]@." "x =" 1 эквивалентно open_box (); print_string "x ="; print_space ();
   print_int 1; close_box (); print_newline ()
. Он выводит x = 1 внутри «горизонтальной или вертикальной» рамки красивого вывода.

val printf : ('a, formatter, unit) format -> 'a

То же, что и fprintf выше, но выводит в get_std_formatter ().

Определена аналогично fun fmt -> fprintf (get_std_formatter ()) fmt, но откладывает вызов get_std_formatter до получения последнего аргумента, требуемого format. При использовании с несколькими доменами вывод из доменов будет чередоваться в точках сброса форматтера, например при вызове Format.print_flush.

val eprintf : ('a, formatter, unit) format -> 'a

То же, что и fprintf выше, но выводит в get_err_formatter ().

Определена аналогично fun fmt -> fprintf (get_err_formatter ()) fmt, но откладывает вызов get_err_formatter до получения последнего аргумента, требуемого format. При использовании с несколькими доменами вывод из доменов будет чередоваться в точках сброса форматтера, например при вызове Format.print_flush.

val sprintf : ('a, unit, string) format -> 'a

То же, что и Format.printf выше, но вместо вывода в форматтер возвращает строку, содержащую результат форматирования аргументов. Обратите внимание, что очередь средства красивого вывода сбрасывается в конце каждого вызова sprintf. Скорее всего, вам следует использовать Format.asprintf, которая позволяет повторно использовать принтеры %a, определённые для Format.fprintf. В отличие от неё, sprintf требует повторного определения принтеров %a и сохранена только для обратной совместимости.

Если требуется несколько связанных вызовов sprintf для вывода данных в одну строку, рассмотрите возможность использования fprintf с предопределённым форматтером str_formatter и вызова flush_str_formatter () для получения итогового результата.

В качестве альтернативы можно использовать Format.fprintf с форматтером, который записывает данные в собственный буфер: сброс форматтера и буфера по завершении красивого вывода вернёт нужную строку.

val asprintf : ('a, formatter, unit, string) format4 -> 'a

То же, что и printf выше, но вместо вывода в форматтер возвращает строку, содержащую результат форматирования аргументов. Тип asprintf достаточно общий, чтобы хорошо взаимодействовать с преобразованиями %a.

  • Начиная с версии 4.01
val dprintf : ('a, formatter, unit, formatter -> unit) format4 -> 'a

То же, что и Format.fprintf, но форматтер является последним аргументом. dprintf "..." a b c — функция типа formatter -> unit, которую можно передать спецификатору формата %t.

Эту функцию можно использовать вместо Format.asprintf, чтобы отложить принятие решений о форматировании. Использование строки, возвращённой Format.asprintf, в контексте форматирования вынуждает принимать решения о форматировании изолированно, и итоговая строка может быть создана преждевременно. Format.dprintf позволяет отложить принятие решений о форматировании до определения окончательного контекста форматирования. Например:

  let t = Format.dprintf "%i@ %i@ %i" 1 2 3 in
  ...
  Format.printf "@[<v>%t@]" t
  • Начиная с версии 4.08
val ifprintf : formatter -> ('a, formatter, unit) format -> 'a

То же, что и fprintf выше, но ничего не выводит. Полезно для игнорирования некоторых данных при условном выводе.

  • Начиная с версии 3.10

Форматированный красивый вывод с продолжениями.

val kfprintf : (formatter -> 'a) ->       formatter -> ('b, formatter, unit, 'a) format4 -> 'b

То же, что и fprintf выше, но вместо немедленного возврата передаёт форматтер своему первому аргументу по завершении вывода.

val kdprintf : ((formatter -> unit) -> 'a) ->       ('b, formatter, unit, 'a) format4 -> 'b

То же, что и Format.dprintf выше, но вместо немедленного возврата передаёт приостановленный принтер своему первому аргументу по завершении вывода.

  • Начиная с версии 4.08
val ikfprintf : (formatter -> 'a) ->       formatter -> ('b, formatter, unit, 'a) format4 -> 'b

То же, что и kfprintf выше, но ничего не выводит. Полезно для игнорирования некоторых данных при условном выводе.

  • Начиная с версии 3.12
val ksprintf : (string -> 'a) -> ('b, unit, string, 'a) format4 -> 'b

То же, что и sprintf выше, но вместо возврата строки передаёт её первому аргументу.

val kasprintf : (string -> 'a) -> ('b, formatter, unit, 'a) format4 -> 'b

То же, что и asprintf выше, но вместо возврата строки передаёт её первому аргументу.

  • Начиная с версии 4.03

Форматированный красивый вывод со списками разнородных аргументов.

Следующие функции работают так же, как соответствующие функции без «l» в названии, но получают аргументы, объединённые в один разнородный список.

Разнородный список служит синтаксически ограниченной коллекцией аргументов, устраняя необходимость в вариантах с продолжениями. Такой подход также делает сообщения об ошибках типов понятнее, особенно когда строка формата не соответствует количеству переданных аргументов.

Например:

    Format.lprintf "%s %d %.02f %c\n" [ "ocaml"; 42; 3.14; 'c' ]
  
module Args: sig .. end

Модуль Args определяет тип разнородного списка, который можно использовать в качестве аргумента функций, подобных printf.

val lfprintf : formatter ->       ('a, formatter, unit) format ->       ('a, unit) Args.t -> unit

То же, что и fprintf выше, но аргументы объединены в один разнородный список.

Например:

    let out = Format.formatter_of_out_channel @@ open_out "some/file.txt" in
    Format.lfprintf out "@[%s@ %d@]@." [ "x ="; 1 ]
  
  • Начиная с версии 5.5
val lprintf : ('a, formatter, unit) format ->       ('a, unit) Args.t -> unit

То же, что и printf выше, но аргументы объединены в один разнородный список.

  • Начиная с версии 5.5
val leprintf : ('a, formatter, unit) format ->       ('a, unit) Args.t -> unit

То же, что и eprintf выше, но аргументы объединены в один разнородный список.

  • Начиная с версии 5.5
val lasprintf : ('a, formatter, unit, string) format4 ->       ('a, string) Args.t -> string

То же, что и asprintf выше, но аргументы объединены в один разнородный список.

  • Начиная с версии 5.5
val ldprintf : ('a, formatter, unit, unit) format4 ->       ('a, unit) Args.t -> formatter -> unit

То же, что и dprintf выше, но аргументы объединены в один разнородный список.

Например:

    let t = Format.ldprintf "%i@ %i@ %i" [ 1; 2; 3 ] in
    ...
    Format.lprintf "@[<v>%t@]" [ t ]
  
  • Начиная с версии 5.5

Примеры

Несколько вводных примеров помогут понять, как используется Format.

У нас есть список l пар (int * bool), который выводится для нас верхнеуровневым интерпретатором:

# let l = List.init 20 (fun n -> n, n mod 2 = 0)
  val l : (int * bool) list =
  [(0, true); (1, false); (2, true); (3, false); (4, true); (5, false);
   (6, true); (7, false); (8, true); (9, false); (10, true); (11, false);
   (12, true); (13, false); (14, true); (15, false); (16, true); (17, false);
   (18, true); (19, false)]
 

Если мы хотим вывести его самостоятельно, без магии верхнеуровневого интерпретатора, можно попробовать так:

  # let pp_pair out (x,y) = Format.fprintf out "(%d, %b)" x y
  val pp_pair : Format.formatter -> int * bool -> unit = <fun>
  # Format.printf "l: [@[<hov>%a@]]@."
    Format.(pp_print_list ~pp_sep:(fun out () -> fprintf out ";@ ") pp_pair) l
    l: [(0, true); (1, false); (2, true); (3, false); (4, true); (5, false);
        (6, true); (7, false); (8, true); (9, false); (10, true); (11, false);
        (12, true); (13, false); (14, true); (15, false); (16, true);
        (17, false); (18, true); (19, false)]

  

Кратко, этот код делает следующее:

  • pp_pair выводит пару bool*int, заключённую в "(" ")". Она принимает форматтер (в который выполняется форматирование) и саму пару. По завершении вывода она возвращает ().
  • Format.printf "l = [@[<hov>%a@]]@." ... l похожа на printf, но содержит дополнительные инструкции форматирования (обозначаемые символом "@"). Пара "@[<hov>" и "@]" образует «горизонтальную или вертикальную рамку».
  • "@." завершает форматирование переводом строки. Она похожа на "\n", но также учитывает состояние Format.formatter. Не используйте "\n" с Format.
  • "%a" — это инструкция форматирования, подобная "%d" или "%s" для printf. Однако если "%d" выводит целое число, а "%s" — строку, то "%a" принимает принтер (типа Format.formatter -> 'a -> unit) и значение (типа 'a), после чего применяет принтер к значению. Это ключевой элемент композиционности принтеров.
  • Мы создаём принтер списка с помощью Format.pp_print_list ~pp_sep:(...) pp_pair. pp_print_list принимает принтер элемента и возвращает принтер списка. Необязательный аргумент ?pp_sep, если он задан, вызывается между элементами для вывода разделителя.
  • В качестве разделителя мы используем (fun out () -> Format.fprintf out ";@ "). Она выводит ";" и затем "@ " — пробел с возможностью переноса (выводится либо " ", либо перевод строки, если рамка вот-вот переполнится). Именно этот "@ " приводит к тому, что список выводится в несколько строк.

Если опустить "@ ", получится некрасивый однострочный вывод:

# Format.printf "l: [@[<hov>%a@]]@."
      Format.(pp_print_list ~pp_sep:(fun out () -> fprintf out "; ") pp_pair) l
  l: [(0, true); (1, false); (2, true); (* ... *); (18, true); (19, false)]
- : unit = ()
    

Как правило, рекомендуется определять собственные принтеры для важных типов в программе. Например, можно определить основные типы геометрических объектов следующим образом:

  type point = {
    x: float;
    y: float;
  }

  type rectangle = {
    ll: point; (* lower left *)
    ur: point; (* upper right *)
  }
  

Для отладки, отображения информации в журналах или вывода в консоль удобно определить принтеры для этих типов. Вот пример того, как это сделать. Обратите внимание: "%.3f" — это принтер float с точностью до 3 знаков после точки; "%f" выводит необходимое количество цифр и может быть довольно многословным; "%h" — принтер шестнадцатеричных чисел с плавающей точкой.

  let pp_point out (p:point) =
    Format.fprintf out "{ @[x=%.3f;@ y=%.3f@] }" p.x p.y

  let pp_rectangle out (r:rectangle) =
    Format.fprintf out "{ @[ll=%a;@ ur=%a@] }"
      pp_point r.ll pp_point r.ur
  

В файле .mli можно написать:

    val pp_point : Format.formatter -> point -> unit

    val pp_rectangle : Format.formatter -> rectangle -> unit
  

Теперь эти принтеры можно использовать с "%a" внутри других принтеров.

 # Format.printf "some rectangle: %a@."
        (Format.pp_print_option pp_rectangle)
        (Some {ll={x=1.; y=2.}; ur={x=42.; y=500.12345}})
  some rectangle: { l={ x=1.000; y=2.000 }; ur={ x=42.000; y=500.123 } }

  # Format.printf "no rectangle: %a@."
        (Format.pp_option pp_rectangle)
        None
  no rectangle:
  

Обратите внимание, как мы объединяем pp_print_option (принтер параметра) и только что определённый принтер прямоугольника, как ранее сделали с pp_print_list.

Более подробное руководство см. в статье «Использование модуля Format».

И напоследок: модуль Format — это отправная точка. В экосистеме OCaml есть библиотеки, упрощающие форматирование и делающие его более выразительным благодаря большему количеству комбинаторов, более кратким именам и другим возможностям. Пример такой библиотеки — Fmt.

Автоматически получать принтеры красивого вывода из определений типов также можно с помощью https://github.com/ocaml-ppx/ppx_deriving или аналогичных средств ppx.

© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/api/Format.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API