pretty v3.0 Release NotesRelease Date: 1987-05-28 // over 35 years ago
🐎 Cured massive performance bug. If you write:
foldl <> empty (map (text.show) [1..10000])
You get quadratic behaviour with V2.0. Why? For just the same reason as you get quadratic behaviour with left-associated (++) chains.
This is really bad news. One thing a pretty-printer abstraction should certainly guarantee is insensitivity to associativity. It matters: suddenly GHC's compilation times went up by a factor of 100 when I switched to the new pretty printer.
I fixed it with a bit of a hack (because I wanted to get GHC back on the road). I added two new constructors to the Doc type, Above and Beside:
<> = Beside $$ = Above
Then, where I need to get to a "TextBeside" or "NilAbove" form I "force" the Doc to squeeze out these suspended calls to Beside and Above; but in so doing I re-associate. It's quite simple, but I'm not satisfied that I've done the best possible job. I'll send you the code if you are interested.
➕ Added new exports: punctuate, hang int, integer, float, double, rational, lparen, rparen, lbrack, rbrack, lbrace, rbrace,
fullRender's type signature has changed. Rather than producing a string it now takes an extra couple of arguments that tells it how to glue fragments of output together:
fullRender :: Mode -> Int -- Line length -> Float -- Ribbons per line -> (TextDetails -> a -> a) -- What to do with text -> a -- What to do at the end -> Doc -> a -- Result
The "fragments" are encapsulated in the TextDetails data type:
data TextDetails = Chr Char | Str String | PStr FAST_STRING
The Chr and Str constructors are obvious enough. The PStr constructor has a packed string (FAST_STRING) inside it. It's generated by using the new "ptext" export.
An advantage of this new setup is that you can get the renderer to do output directly (by passing in a function of type (TextDetails -> IO () -> IO ()), rather than producing a string that you then print.