Use wadler's pretty printer to align output in more subtle way

Hi folks, I’m using fpottier/pprint to pretty-print code.

Pretty printer is convenience to control indentation when newline happened. It’s easy to use combinator align to align arg2 and arg3 with arg1, like this:

// string "someFunc" ^/^ align (group (string "arg1" ^/^ string "arg2" ^/^ "arg3"))

someFunc  arg1

It just like pretty printer automatically insert space after newline for me. But is it possible to make pretty printer insert spaces in any place I want to align with other line?

For example, I want to keep : and = in same column:

  var a         : long    = 100
  var long_name : integer = 20
  var myVar     : string  = "hello"

I don’t think that pprint supports this, the only form of indentation supported is whitespace at the beginning of the line and not spacing inside the line. One would need to add new combinators and new semantics to PPrint to support this, and it is not obvious how to do it.

Format does support this with the tabulation boxes.

Fun fact: this would be trivial if our text-rendering tools supported elastic tabstops, which is my favorite semantics for \t, but oh well, this is not standard unfortunately.

1 Like

Basically the only concept of pprint is that document fragments can format differently depending on whether the group they belong to (1) fits on a singleline, or (2) needs to be broken in several lines to fit. In the context of tabulations as in the example above

var <some name> : <some type> = <some expr>
var <some name> : <some type> = <some expr>

There are two important conceptual problems:

  • The pretty-printing of a given group depends on the pretty-printing of groups after it, which is a deviation from PPrint’s approach. One could introduce the notion that, sometimes, the pretty-printer needs to go ahead and preprint more documents to make “more global” (but still localized to a given tabulation array) decisions.
  • There is no well-defined “target width” for each column, to decide whether a given group needs to be broken or not. For whole lines we know, the target width is the difference between the ideal line length and the current indentation level. Here as long as there are at least two columns we don’t know which width to assign to both of them

A natural idea would be to try printing with the line length as the “target width” of each column, and then reduce that for each column as long as the resulting pretty-printing choices do not fit. But this gives an astronomical number of retries, very different from PPrint’s efficient algorithm. Clearly some algorithmic cleverness would be needed to get an acceptable result, and we are not even sure what the specification should be.

Note: this may be related to Jean-Philippe Bernardy’s work on a Pretty but not Greedy Printer.

1 Like