prettyprinter icon indicating copy to clipboard operation
prettyprinter copied to clipboard

`space`s not collapsed

Open effectfully opened this issue 4 years ago • 7 comments

The following snippet

putStrLn . renderString . layoutPretty defaultLayoutOptions $
    pretty "a" <+> mempty <+> pretty "b"

gives this output:

a  b

(two spaces between a and b). Most of the time I want spaces to collapse i.e. to have

x <> space <> space === x <> space

because I often write things like x <+> (if b then y else mempty) <+> z and I want to have one space between x and z when b is False. I think, pretty (the library) works this way.

With the current behaviour I have to structure my pretty-printers in a weird non-compositional way. Is it maybe possible to add a layoutCollapseSpaces :: Bool option to LayoutOptions?

effectfully avatar Feb 15 '20 22:02 effectfully

I've never used pretty but according to "A prettier printer" it has different concatenation primitives than the Wadler/Leijen style pretty-printers, so it might behave as you desire here.

Is it maybe possible to add a layoutCollapseSpaces :: Bool option to LayoutOptions?

Maybe, but it seems tricky to avoid collapsing subsequent spaces when they were intentionally inserted.

I think a better alternative might be to use something like this variant of hsep:

hsep' :: [Doc ann] -> Doc ann
hsep' = hsep . filter (not . isEmpty)
  where
    isEmpty Empty = True
    isEmpty _ = False
hsep' [x, if b then y else mempty, z]

sjakobi avatar Feb 15 '20 22:02 sjakobi

… or you could use a variant of <+>:

(<++>) :: Doc ann -> Doc ann -> Doc ann
Empty <++> y = y
x <++> Empty = x
x <++> y = x <> Char ' ' <> y
infixr 6 <++>

sjakobi avatar Feb 16 '20 10:02 sjakobi

For reference, there's an old SO question regarding zero-height documents. IMHO that's a related problem where a solution could also involve filtering out the empty documents.

EDIT: wl-pprint has the same problem.

sjakobi avatar Feb 19 '20 12:02 sjakobi

Thank you!

The solution that you proposed works for me.

Feel free to close the issue if you don't think it's worth keeping it open.

effectfully avatar Feb 22 '20 14:02 effectfully

Since there are multiple people who have trouble with the handling of empty documents, I'll keep this open to discuss possible solutions.

sjakobi avatar Feb 22 '20 16:02 sjakobi

The problem is that <+> is not concatenation, but »put a space between these, no matter what«. We could do something similar to what GHC does – remove duplicate empty lines etc – but that brings its own complexities. For example, it’s a priori not possible to decide whether a document is empty (it might be layout-dependent, e.g. using pageWidth). So double whitespace collapse would need to be a special case in the layouter and only happen when the user requests it in some way.

I think it’s easier to solve this at the individual user’s level; these little, superficially convenient and desirable features usually result in loads of very subtle special cases that differ for each user anyway, so there is no one size fits all way of making the library »smart«.

quchen avatar Mar 02 '20 10:03 quchen

After stumbling across GHC's prettyprinter plans I found a related discussion in https://github.com/quchen/prettyprinter/issues/34.

sjakobi avatar Mar 02 '20 20:03 sjakobi