Wadler's Pretty printer. Use the constructor functions to build up a Doc and
lay it out to fit a page width using the pretty function.
Renders a document to a string, fitting it within the given column width.
The algorithm makes greedy left-to-right decisions: when a group fits on the
remaining line, it stays flat; otherwise it breaks.
doc = group (string "aaa" |> a line |> a (string "bbb"))
pretty 10 doc == "aaa bbb" -- fits in 10 columns
pretty 5 doc == "aaa\nbbb" -- too wide, breaksAn empty document that produces no output.
Unlike string "", empties are filtered out by join, lines, words, etc.
This prevents double separators when some items are conditionally absent:
words [ string "a", empty, string "b" ] -- "a b", not "a b"
-- Conditional content:
words [ string "hello", if showName then string name else empty ]A single space character. Equivalent to char ' '.
string "hello" |> a space |> a (string "world") -- "hello world"Creates a document from a string. This is the primary way to add text content.
pretty 80 (string "hello") == "hello"
string "let" |> a space |> a (string "x = 1") -- "let x = 1"Creates a tagged string for syntax highlighting. Use with Pretty.Renderer
to produce HTML or other formatted output.
type Tag = Keyword | Literal
taggedString "let" Keyword |> a space |> a (taggedString "42" Literal)Creates a document from a single character.
char '(' |> a (string "x") |> a (char ')') -- "(x)"Concatenates two documents. The first argument comes before the second.
append (string "hello") (string "world") -- "helloworld"Usually it's more convenient to use a for pipelines, or join/words/lines
for lists.
Flip of append for use in pipelines. Read as "and":
string "if"
|> a space
|> a (string "x > 0")
|> a space
|> a (string "then")
-- "if x > 0 then"Joins documents with a separator between each pair. Empty documents are filtered out to prevent double separators.
join (string ", ") [ string "a", string "b", string "c" ] -- "a, b, c"
join (string ", ") [ string "a", empty, string "c" ] -- "a, c" (not "a, , c")See also words (join with space), lines (join with line), separators.
Joins documents with line between each. Equivalent to join line.
lines [ string "one", string "two", string "three" ]
-- "one\ntwo\nthree"Wrap in group for flexible breaking:
group (lines [ string "a", string "b" ])
-- Wide: "a b" | Narrow: "a\nb"Joins documents with a separator that appears both when flat and when broken. Useful for leading-comma or leading-pipe style:
separators ", " [ string "a", string "b", string "c" ] |> group
-- Wide: "a, b, c"
-- Narrow: "a\n, b\n, c"
separators "| " [ string "A", string "B" ] |> group
-- Wide: "A| B"
-- Narrow: "A\n| B"Joins documents with softline (each break decides independently).
softlines [ string "one", string "two", string "three" ]
-- Each softline independently becomes space or newline based on fitUnlike group (lines [...]) where all breaks happen together, here each
break point makes its own decision.
Joins documents with spaces. Equivalent to join space.
words [ string "hello", string "world" ] -- "hello world"Empty docs are filtered out, preventing double spaces.
Left fold over a list, starting from empty. Useful for custom joining:
-- Join with " -> " between items
fold (\item acc ->
if acc == empty then string item
else acc |> a (string " -> ") |> a (string item)
) [ "a", "b", "c" ]
-- "a -> b -> c"Try to lay out a document on one line; if it doesn't fit, break it.
This is the key combinator for flexible layouts. It creates a choice between the flattened version (line breaks become spaces) and the original.
items = string "one" |> a line |> a (string "two") |> a line |> a (string "three")
pretty 20 (group items) == "one two three" -- fits
pretty 10 (group items) == "one\ntwo\nthree" -- doesn't fit, breaksNested groups break outside-in: the outer group breaks first, inner groups may still fit on their lines.
A line break that becomes a space when flattened by group.
-- Without group: always breaks
string "a" |> a line |> a (string "b") -- "a\nb"
-- With group: breaks only if needed
group (string "a" |> a line |> a (string "b"))
-- Wide: "a b" (line becomes space)
-- Narrow: "a\nb" (line breaks)Use tightline if you want no space when flattened.
A line break that becomes nothing when flattened by group.
Use this before closing delimiters to avoid unwanted spaces:
-- Array formatting
group (
char '[' |> a tightline
|> a (string "items")
|> a tightline |> a (char ']')
)
-- Wide: "[items]" (no spaces)
-- Narrow: "[\nitems\n]"Compare with line which would produce "[ items ]" when flat.
A line break that tries to be a space. Equivalent to group line.
Unlike line inside a group, each softline makes its own independent
break decision:
string "a" |> a softline |> a (string "b") |> a softline |> a (string "c")
-- Might render as: "a b\nc" if "a b" fits but "a b c" doesn'tAligns subsequent lines to the current column position. Unlike nest which
adds a fixed indent, align indents relative to where you are now.
string "let " |> a (align (lines [ string "x = 1", string "y = 2" ]))
-- "let x = 1\n y = 2"
-- ^--- aligned to column 4 (after "let ")Useful for hanging indentation that adapts to context.
Adds indentation to all line breaks inside a document. The first line is NOT indented—only lines after breaks.
string "{" |> a (nest 4 (line |> a (string "body"))) |> a line |> a (string "}")
-- "{\n body\n}"Common mistake—nest around content without a line break inside:
nest 4 (string "no effect") -- just "no effect", no indentationThe line break must be INSIDE the nest for indentation to apply.
Combines align with additional nesting. Equivalent to align (nest n doc).
string "fn(" |> a (hang 2 (lines [ string "arg1", string "arg2" ])) |> a (string ")")
-- "fn(arg1\n arg2)"
-- ^--- aligned to column 3, plus 2 more = column 5Indents the first line AND all subsequent lines by the given amount.
indent 4 (lines [ string "one", string "two" ])
-- " one\n two"Compare with nest which only affects lines after breaks, not the first line.
Wraps a document with left and right delimiters.
surround (string "<<") (string ">>") (string "content") -- "<<content>>"See also parens, braces, brackets for common cases.
Wraps a document in parentheses.
parens (string "x + y") -- "(x + y)"Wraps a document in curly braces.
braces (string "x: 1") -- "{x: 1}"Wraps a document in square brackets.
brackets (string "1, 2, 3") -- "[1, 2, 3]"Tags all strings in a document for syntax highlighting.
type Tag = Error
setTag Error (words [ string "undefined", string "variable" ])
-- Both strings will be tagged as ErrorConditionally update tags based on string content and current tag.
-- Tag numbers as literals
updateTag (\s _ ->
if String.all Char.isDigit s then Just Literal else Nothing
) doc
-- Remove all tags
updateTag (\_ _ -> Nothing) doc
A document describes possible layouts for pretty printing. The type parameter
tallows tagging text for syntax highlighting.Build documents with combinators like
string,line,nest, then render withpretty: