Module Core_extended.Pp

Functional pretty printing.

This is a pretty printing library originally written by Christian Lindig and released under the Copyleft licence for the c-- project. The design of this library is discussed in the article "Strictly pretty".

The pretty printer provided by the Pp module is intended for tree-like structures. Documents are represented by an abstract type t. A document can be printed to a file or a string and during this process the pretty printer decides about the final outcome of the document. The only parameter it takes into account is the total line width and the number of characters a sub-document occupies.

A document of type t can be very small entity like a single word. Functions combine small documents to larger ones which then can be pretty printed.

type t
val empty : t

The empty document is pretty printed to the empty string. Typically empty is used in one branch of an if statement.

val ($) : t ‑> t ‑> t

The infix operator x $ y concatenates two documents x and y into a larger one. It does not introduce any space or other separation between the two original documents.

val text : string ‑> t

The text function turns a string into a document. The pretty printed representation of the resulting document is exactly the string text was applied to.

val break : t

The important points in a document are so-called breaks. A break can be either represented by a single space or a newline followed by a number of spaces. The pretty printer makes this decision based on the available space. So think of a break as a space that might come out as a newline. To give the pretty printer enough flexibility documents must be joined with breaks: x $ break $ y.

val break_null : t

break_null behaves like break except it does not insert anything when no newline is inserted.

val break_with : string ‑> t

The space character used by break my be not always appropriate. The function break_with s behaves like break except that it uses a user supplied string s instead of the space.

Grouping and nesting

The pretty printer considers the representation of breaks not one by one but looks at all breaks of a sub-document. Documents are structured into sub-documents by group-operators. Different group operators exist to control the behavior of the pretty printer.

val nest : int ‑> t ‑> t

When the pretty printer decides to represent a break as a newline it also prints some spaces after it to indent the following line. The number of spaces is controlled by the nest operator that takes a document as argument: nest n d. All breaks turned to newlines inside document d are followed by n spaces. The nest operator nests properly such that it takes the spaces introduced by nests on the outer level also into account.

val hgrp : t ‑> t

A group operator takes a document and let it become a group. The hgrp operator creates a horizontal group. Breaks inside a hgrp are never turned into newlines but always come out as spaces. This group has a very limited usefulness because it easily overruns any given line length.

val vgrp : t ‑> t

The vgrp operator creates a vertical group. All breaks inside a vgrp are represented as newlines followed by spaces. Although all breaks come out as newlines the indentation of lines inside the group may differ: nesting is independent of grouping and thus different nesting levels can be active in the same group. Because of the fixed pretty printing strategy vgrps are used mostly at the top level of documents only.

val agrp : t ‑> t

The automatic group agrp is the most versatile. Breaks inside this group are either all turned into newlines (followed by spaces), or into spaces. Subgroups are, of course, not affected but considered individually.

val fgrp : t ‑> t

The break policy inside an agrp is fixed for all breaks of the group. Inside a flexible group fgrp each break is considered individually: when the document up to the next break fits into the current line the break comes out as space. Otherwise it comes out as newline followed by spaces.

Pretty Printing

val to_string : ?⁠width:int ‑> t ‑> string
val to_file : ?⁠width:int ‑> Pervasives.out_channel ‑> t ‑> unit

Auxiliaries

val list : sep:t ‑> f:('a ‑> t) ‑> 'a list ‑> t

A list of objects which are seperated by some seperator is very common. The list sep f function takes care to insert the separator only between objects but not at the end of the list. It creates a sep separated list. Individual items are printed using f. For the common case where commas are used for separating we also provide an extra definition

val commalist : f:('a ‑> t) ‑> 'a list ‑> t
val ($/) : t ‑> t ‑> t

Instead of writing x $ break $ y to insert a break it is convenient to define an operator for this: x ^/ y joins x and y with a break.

val ($//) : t ‑> t ‑> t

Joins two documents with a break_null.

val block : ?⁠indent:int ‑> f:('a ‑> t) ‑> 'a list ‑> t

A block contains objects xs formatted by f and enclosed by curly braces. Its body will be indented in case it does not fit on a single line. The default indentation is 4

module Infix : sig ... end
val hlist : t list ‑> t
hlist [x1,..,xn] = hgrp [x1; break; x2; ...; break; xn)
val vlist : t list ‑> t
vlist [x1,..,xn] = vgrp [x1; break; x2; ...; break; xn)
val alist : t list ‑> t