Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding emptyLine document #26

Open
osa1 opened this issue Mar 14, 2015 · 2 comments
Open

Adding emptyLine document #26

osa1 opened this issue Mar 14, 2015 · 2 comments

Comments

@osa1
Copy link
Contributor

osa1 commented Mar 14, 2015

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:

  1. 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.

  2. 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".

@dterei
Copy link
Member

dterei commented Mar 19, 2015

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.

yamadapc added a commit to beijaflor-io/haskell-language-conf that referenced this issue Aug 23, 2016
While we wait for haskell/pretty#26, we patch the output.

Not a pretty fix, but it'll work for us.

This closes #3.
@andreasabel
Copy link
Member

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 Docs 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 (mapped), 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants