osa1
osa1

Reputation: 7078

Text.PrettyPrint a better way to set indentation

I have a pretty-printer like that:

somefun = text "woo" $+$ nest 4 (text "nested text") $+$ text "text without indent"
fun = text "------" $+$ somefun

What I want from it is to print this:

------ woo
    nested text
text without indent

But it prints:

------
woo
    nested text
text without indent

I can understand why it prints like this, but I'm having trouble to do what I want. One solution I find was this:

somefun p = p <+> text "woo" $+$ nest 4 (text "nested text") $+$ text "text without indent"
fun = somefun (text "------")

That is, I'm passing the Doc which I want my next Doc's indentation to be based on. This solves my problem but I'm looking for better ways to do this.

Upvotes: 0

Views: 466

Answers (1)

AndrewC
AndrewC

Reputation: 32455

Your pass-the-Doc-as-an-argument solution is good. Once you've combined into a single Doc, you can't split it apart again, so here are two ways that use lists instead:

Alternative 1

Another way of doing this is to use [Doc] instead of Doc for your subsequent text, if you want to treat the lines differently, then recombine using something like

(<+$) :: Doc -> [Doc] -> Doc
doc <+$ [] = doc 
doc <+$ (d:ds) = (doc <+> d) $+$ foldr ($+$) empty ds

somefun :: [Doc]
somefun = [text "woo",
    nest 4 (text "nested text"),
    text "text without indent"]

fun :: Doc
fun = text "------" <+$ somefun

This gives you

*Main> fun
------ woo
    nested text
text without indent

Alternative 2

You could rewrite this solution another way keeping lists, if you like to keep indenting the top line:

(<+:) :: Doc -> [Doc] -> [Doc]
doc <+: [] = [doc] 
doc <+: (d:ds) = (doc <+> d) : ds -- pop doc in front.

We'll need to put those together into a single Doc at some stage:

vsep = foldr ($+$) empty

Now you can use : to put a line above, and <+: to push a bit in front of the top line:

start = [text "text without indent"]
next  = nest 4 (text "nested text") : start
more  = text "woo" : next
fun   = text "------" <+: more
extra = text "-- extra! --" <+: fun

Test this with

*Main> vsep fun
------ woo
    nested text
text without indent

*Main> vsep extra
-- extra! -- ------ woo
    nested text
text without indent

The main issue is that if you use [Doc] instead of Doc it's almost as if you're not using the pretty-print library! It doesn't matter, though, if it's what you need.

Upvotes: 2

Related Questions