pretty
pretty copied to clipboard
Adding emptyLine document
Empty lines are useful to separate blocks in printed programs, but unless I'm getting the API wrong, currently only way to produce a empty newline is to use text ""
. empty
doesn't work, because it's unit of $$
and $+$
.
The problem with text ""
is that when combined with nest
, it produces trailing white space. For example, this:
nest 4 (text "" $+$ text "block")
Generates this:
$
block$
I propose implementing an emptyLine
document, like this:
emptyLine :: Doc a
emptyLine = NilAbove Empty
This works fine, for example, this program:
print $ nest 4 $ emptyLine $$ text "blah"
print $ nest 4 $ text "blah" $+$ emptyLine
prints this:
$
blah$
blah$
$
$
Which is not bad, but now it's printing an extra new line at the end.
So I think there are two problems:
-
This use of
NilAbove
is actually invalidating some internal invariants. Even though I couldn't manage to produce a broken example with this new doc, in the code it's mentioned that:1) The argument of NilAbove is never Empty. Therefore a NilAbove occupies at least two lines.
Which this change clearly invalidates.
-
We need to make some changes in some of the combinators to handle extra newline printed in the case of
text "blah" $+$ emptyLine
. I think it's printed because of this invalidated invariant.
So at this point I'm hoping to get some comments and ideas. Do you think this is a correct way of doing this? Is there any other way to produce new lines without producing trailing white spaces?
Also, some help with changing internals would be great.
Thanks.
UPDATE: I just tried this program:
print $ nest 4 $ emptyLine $$ (nest 4 $ text "blah")
print $ nest 4 $ (nest 4 $ text "blah") $+$ emptyLine
And it produced this:
$
blah$
blah$
$
$
It's good to see that next line after the blah
is not indented. Last indented empty line should be fixed when we remove that line.
UPDATE 2: Here's a broken example:
print $ nest 4 $ emptyLine <> (nest 4 $ text "blah")
print $ nest 4 $ (nest 4 $ text "blah") <> emptyLine
Output:
$
blah$
blah$
$
An emptyLine
should never be indented, that's the whole point of it. Documentation sometimes mention "height" and "width", maybe we should be able to say "emptyLine has height 1 and width 0".
I'm not sure what the best approach to this is right now sorry. On the surface it seems that it may be challenging to get what you want as it sort of breaks the modularity here of things like nest
. I'm not going to have any time to look at this for a few weeks sorry, but please ping me again if I forget.
Me too.
I am hitting the same problem, trailing spaces produced by nest
when document contains empty lines. I second the original proposal, to add the concept of an empty line to the internal document structure and to expose it as emptyLine
with one law being nest n emptyLine == emptyLine
.
The current situation is bad since it forces the programmer into non-compositionality when using the pretty printing framework. By this I mean that Doc
s cannot be combined compositionally, but it is often needed to keep a document containing empty lines as [Doc]
where the empty lines go between the documents in such a list. On such a list of documents, nest
can be safely applied (map
ped), and only in the very end this list may be converted into a single document, inserting the empty lines between. This is an ugly workaround for the missing functionality of this library, which is the de facto standard pretty printer still.