doc.txt

PPrint

_PPrint_
_pprint_

This collection provides two files:

 _pprint.ss_: a pretty-printing library
 _haskell.ss_: a compatibility library with names similar to Haskell
 _idioms.ss_: combinators for common programming language patterns

This library is based on Daan Leijen's PPrint library for Haskell:

    http://www.cs.uu.nl/~daan/pprint.html

The implementation is also based on Ralph Becket's port of PPrint for
the strict functional/logic language Mercury:

    http://www.cs.mu.oz.au/research/mercury/information/doc-release/library_37.html

See _design.txt_ for details on the implementation.


======================================================================

pprint.ss
---------

FRONT END ------------------------------------------------------------

> type doc

A _doc_ is an abstract datatype representing a pretty document. Pretty-printing
involves applying the constructors provided by this library to construct a
pretty document and then applying one of the three pretty printing functions to
that document (_pretty-print_, _pretty-format_, or _pretty-markup_).

> (doc? x) :: any -> boolean

Determines whether a value is a member of the _doc_ datatype.

When using the `markup' constructor, the _doc_ type may be thought of
as a parameterized type:

> type (doc a)

See the documentation for the _markup_ constructor for details.

> (pretty-print d [out width]) :: doc [output-port nat] -> any

Pretty prints the doc `d' to the output `out' (which defaults to the current
value of _current-output-port_) with a maximum page width of `width' (which
defaults to the current value of _current-page-width_).

> (pretty-format d [width]) :: doc [nat] -> string

Pretty prints the doc `d' to a string width a maximum page width of `width'
(which defaults to the current value of _current-page-width_).

> (pretty-markup d combine [width]) :: (doc a) ((union string a) (union string a) -> (union string a)) [nat] -> (union string a)

Pretty prints the doc `d' to an instance of type `a', which is determined by the
type of the `markup' nodes in the doc, with a maximum page width of `width'
(which defaults to the current value of _current-page-width_).

The process of generating the markup relies on the ability to concatenate
strings or markup, and this concatenation is dependent on the type `a'. So the
`combine' argument must be provided to concatenate fragments of
marked-up text.

> (current-page-width [w]) :: (parameterof nat)

A parameter specifying the default maximum page width for pretty printing.


BASIC COMBINATORS ----------------------------------------------------

> empty :: doc

The empty document, which contains the empty string.

> (char c) :: character -> doc

Renders a document containing the single character `c'.

> (text s) :: string -> doc

Renders a document containing the constant string `s'.

> (nest n d) :: nat doc -> doc

Renders document `d' with the current indentation level increased by `n'.

NOTE: The _nest_ combinator does NOT affect the current line's
indentation. Indentation is only inserted after a _line_ or a
_break_.

Example:

    (pretty-format (nest 4 (text "not indented")))
    ; => "not indented"

    (pretty-format (nest 4 (h-append (text "not indented") line (text "indented"))))
    ; => "not indented\n    indented"

> (label s d) :: string doc -> doc

Renders document `d' with the current indentation suffixed by the string `s'.

> (markup f d) :: ((union string a) -> (union string a)) (doc a) -> (doc a)

Creates a document node with a markup transformer, which is applied by
_pretty-markup_ to produce a pretty-printed document with markup
information. The markup is assumed not to affect the width of the
string. This allows you, for example, to produce X-expressions from
pretty-printed source, e.g.:

    (pretty-markup (markup (lambda (x) `(em ,x)) (text "hello, world!")))
    ; => (em "hello, world!")

> (group d) :: doc -> doc

Renders document `d' with all line breaks removed, if it fits on a single line;
otherwise simply renders `d' as-is.

> line :: doc

Renders a document containing a line break, which is replaced with a single
space when rendered in the context of a `group'.

> break :: doc

Renders a document containing a line break, which is replaced with the empty
string when rendered in the context of a `group'.

> soft-line :: doc

soft-line = (group line)

> soft-break :: doc

soft-break = (group break)


DOC COMBINATORS ------------------------------------------------------

> (h-append d ...) :: doc ... -> doc

Appends documents `d ...'.

> (hs-append d ...) :: doc ... -> doc

Appends documents `d ...' with each successive pair of documents separated by
_space_.

> (v-append d ...) :: doc ... -> doc

Appends documents `d ...' with each successive pair of documents separated by
_line_.

> (vs-append d ...) :: doc ... -> doc

Appends documents `d ...' with each successive pair of documents separated by
_soft-line_.

> (vb-append d ...) :: doc ... -> doc

Appends documents `d ...' with each successive pair of documents separated by
_break_.

> (vsb-append d ...) :: doc ... -> doc

Appends documents `d ...' with each successive pair of documents separated by
_soft-break_.


LIST COMBINATORS -----------------------------------------------------

> (h-concat ds) :: (listof doc) -> doc

Concatenates documents `ds'.

> (hs-concat ds) :: (listof doc) -> doc

Concatenates documents `d ...' with each successive pair of documents separated
by _space_.

> (v-concat ds) :: (listof doc) -> doc

Concatenates documents `d ...' with each successive pair of documents separated
by _line_.

> (vs-concat ds) :: (listof doc) -> doc

Concatenates documents `d ...' with each successive pair of documents separated
by _soft-line_.

> (v-concat/s ds) :: (listof doc) -> doc

(v-concat/s ds) = (group (v-concat ds))

Concatenates documents `ds' horizontally, separated by spaces, if they all fit
on one line; otherwise concatenates them vertically.

> (vb-concat ds) :: (listof doc) -> doc

Concatenates documents `d ...' with each successive pair of documents separated
by _break_.

> (vsb-concat ds) :: (listof doc) -> doc

Concatenates documents `d ...' with each successive pair of documents separated
by _soft-break_.

> (vb-concat/s ds) :: (listof doc) -> doc

(vb-concat/s ds) = (group (vb-concat ds))

Concatenates documents `ds' horizontally if they all fit on one line; otherwise
concatenates them vertically.

> (apply-infix d ds) :: doc (listof doc) -> (listof doc)

Concatenates documents `ds', with each successive pair of documents separated by
document `d'.


FILLERS --------------------------------------------------------------

> (fill n d) :: nat doc -> doc

Renders document `d' with enough spaces to pad its width to `n' (or no spaces if
the width is already `n' or greater).

Example:

    (pretty-print (hs-append (text "let")
                             (align (vb-append (hs-append (fill 6 (text "empty"))
                                                                  (text "::")
                                                                  (text "Doc"))
                                               (hs-append (fill 6 (text "nest"))
                                                                  (text "::")
                                                                  (text "Int -> Doc -> Doc"))
                                               (hs-append (fill 6 (text "linebreak"))
                                                                  (text "::")
                                                                  (text "Doc"))))))
    ; =>
    ; let empty  :: Doc
    ;     nest   :: Int -> Doc -> Doc
    ;     linebreak :: Doc

> (fill/break n d) :: nat doc -> doc

Renders document `d' with enough spaces to pad its width to `n', or if the width
is already `n' or greater, increases the nesting level by `n' and appends a
_line_.

Example:

    (pretty-print (hs-append (text "let")
                             (align (vb-append (hs-append (fill/break 6 (text "empty"))
                                                                        (text "::")
                                                                        (text "Doc"))
                                               (hs-append (fill/break 6 (text "nest"))
                                                                        (text "::")
                                                                        (text "Int -> Doc -> Doc"))
                                               (hs-append (fill/break 6 (text "linebreak"))
                                                                        (text "::")
                                                                        (text "Doc"))))))
    ; =>
    ; let empty  :: Doc
    ;     nest   :: Int -> Doc -> Doc
    ;     linebreak
    ;            :: Doc


ALIGNMENT ------------------------------------------------------------

The alignment combinators were introduced in Daan Leijen's PPrint library. These
combinators are useful in practice but more expensive than other
combinators. They are also not always optimal, since they determine their layout
relative to the current column.

> (align d) :: doc -> doc

Renders document `d' with the nesting level set to the current column.

> (hang n d) :: nat doc -> doc

(hang n d) = (align (nest n d))

Renders document `d' with the nesting level set to the current column plus `n'.

> (indent n d) :: nat doc -> doc

Renders document `d' indented by `n' spaces.


DOCUMENT CONSTANTS ---------------------------------------------------

> comma :: doc
> semi :: doc
> colon :: doc
> lparen :: doc
> rparen :: doc
> lbracket :: doc
> rbracket :: doc
> lbrace :: doc
> rbrace :: doc
> langle :: doc
> rangle :: doc
> space :: doc
> ellipsis :: doc
> squote :: doc
> dquote :: doc
> dot :: doc
> backslash :: doc
> equals :: doc


idioms.ss
----------------

[TODO: coming soon]


haskell.ss
-----------------

For those who are more familiar with the names in the Haskell library,
this library is provided as a compatibility mode. (This might be
useful for porting existing Haskell code, for example.)

> empty  = empty
> char   = char
> text   = text
> nest   = nest
> group  = group

> line       = line
> linebreak  = break
> softline   = soft-line
> softbreak  = soft-break

> <>    = h-append
> <+>   = hs-append
> <$>   = v-append
> </>   = vs-append
> <$$>  = vb-append
> <//>  = vsb-append

> hcat       = h-concat
> hsep       = hs-concat
> vsep       = v-concat
> fill-sep   = vs-concat
> sep        = v-concat/s
> vcat       = vb-concat
> fill-cat   = vsb-concat
> cat        = vb-concat/s
> punctuate  = apply-infix

> fill        = fill
> fill-break  = fill/break

> align   = align
> hang    = hang
> indent  = indent

> comma     = comma
> semi      = semi
> colon     = colon
> lparen    = lparen
> rparen    = rparen
> lbrace    = lbrace
> rbrace    = rbrace
> lbracket  = lbracket
> rbracket  = rbracket
> langle    = langle
> rangle    = rangle
> space     = space
> ellipsis  = ellipsis
> squote    = squote
> dquote    = dquote
> dot       = dot
> backslash = backslash
> equals    = equals


EXAMPLES -------------------------------------------------------------

[TODO: coming soon]


REFERENCES -----------------------------------------------------------

[1] Ralph Becket, pprint.m (2002)
    http://www.cs.mu.oz.au/research/mercury/information/doc-latest/mercury_library/pprint.html

[2] John Hughes, "The Design of a Pretty-Printing Library" (1995)
    http://www.cs.chalmers.se/~rjmh/Papers/pretty.html

[3] Daan Leijen, "PPrint, a Prettier Printer" (2001)
    http://www.cs.uu.nl/~daan/download/pprint/pprint.html

[4] Simon Peyton Jones, "A Pretty-Printer Library in Haskell" (1997)
    http://research.microsoft.com/~simonpj/downloads/pretty-printer/pretty.html

[5] Philip Wadler, "A Prettier Printer" (1998)
    http://homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier