Pretty Expressive Printer for Gren
A Gren implementation of the Pretty Expressive Printer, ported from the OCaml implementation.
This library implements an optimal pretty printer. Given a page-width limit
and a cost model, it searches all possible layouts and selects the one with
the lowest cost. Documents are constructed from combinators and rendered with
prettyFormat or prettyFormatInfo.
Basic usage:
import PrettyExpressive as P
-- Create a CostFactory, for measuring optimality ("prettiness")
cf : P.CostFactory P.DefaultCostTuple
cf =
P.defaultCostFactory { pageWidth = 80, computationWidth = Nothing }
-- Create the document (sequences of pretty-printing directives)
document : P.Doc
document =
(P.text "hello" |> P.concat (P.text " world"))
-- Render the document to a String
printed : Maybe String
printed =
P.prettyFormat cf document
Gren-specific design note: The OCaml original used per-node mutable hash
tables (indexed by (column, indent) pairs) to memoize intermediate results,
and a global counter to assign unique IDs to nodes for sharing detection.
Neither technique is implemented here in Gren, as it greatly increases
the complexity of the code. The omission is unlikely to matter
for typical documents; only extremely large or heavily shared document trees
may be noticeably slower.
Notes
The ACM article describing the algorithm presents only a few Doc constructors. They are the most important:
- text
- nl
- concat
- nest
- group
In the article, the CostFactory has a very small, simple itnerface.
The OCaml implementation provides many more constructors, and its CostFactory has a much more complicated interfae, to support these new constructors. This Gren package provides all the same constructors as the OCaml version does, and has the same more-complicated CostFactory interface.
This Gren package also adds another helper constructor, and is open to adding more as needed:
- concat_array
References
- ACM Reference Page
- ACM PDF from October 2023
Other implementations
- OCaml information
- OCaml sources
- Haskell in the src/Floskell directory
- Racket
- Rust information
- Rust sources in the pretty-expressive directory