
Evan Laforge schrieb:
byorgey: fons: I can't explain it, all I know is that you must set it to 1 or else it does bizarre things fons: hahah, ok fons: byorgey: that's funny considering its default value is 1.5 byorgey: if you set it to 1 then lineLength means what you think it should byorgey: fons: EXACTLY
Excellent, thanks for solving a nagging problem I couldn't be bothered to track down. I was wondering why my pretty printing was a little messed up and slightly too wide.
And isn't 100 columns a bit non-standard for a default? I thought 80 columns had more traction? I know that's what my terminals are at...
Hi, The "ribbon length" is used when choosing the most beautiful layout: I'll just summarize the relevant section from John Hughes paper (http://www.cs.chalmers.se/~rjmh/Papers/pretty.ps), which explains it very nicely: "... Using [the criterion whether the text fits on the page] alone tends to produce layouts such as
for i = 1 to 100; for j=1 to 100; for k=1 to 100; a[i][j][k]:=0;
which fits on a page {==> line-width} but cannot be described as pretty. We therefore impose an additional constraint limiting the number of characters on each line [==> ribbon-width} [...]
for i = 1 to 100 for j = 1 to 100 ... "
So the pretty printer tries to avoid sequences (ribbons) of characters which are longer than ribbon_length, when using auto layout stuff like `sep'. In the source code, we have (paraphrased)
ribbon_length = line_length / ribbonsPerLine
and
choose_nicest_layout indent p q = if p + indent fits into line_length and p fits into ribbon_length then p else q
Working example below. I'm not sure 80 characters is still standard when _pretty_-printing - the longest line in Text.PrettyPrint.HughesPJ is 109 characters wide ;) Setting the ribbon ratio to 1 essentially disables the ribbon feature. Btw: while studying the source code, I also found the cat (and sep) can be implemented in a more space efficient way (currently, cat needs to evaluate every document in a list to yield some output). Does this make sense (see below) ? cheers, benedikt -- * ribbon example
-- lineLength = 26, ribbonsPerLine = 1.5 ==> ribbonLength = 17 -- therefore, we have a line break if width-indent > 17 or width > 26 testStyle = Style { mode = PageMode, lineLength = 26, ribbonsPerLine = 1.5 } ribbonTest = renderStyle testStyle $
-- use hsep as width == 17 <= ribbonLength sep [ txt 5, txt 11 ]
-- linebreak, as width-indent = width = 18 > ribbonLength $+$ sep [ txt 5, txt 12 ]
-- use hsep, as width - indent == 17, and width == 22 < lineLength $+$ sep (map (nest 5) $ [txt 5, txt 11] )
-- linebreak, as width would be 27 > lineLength $+$ sep (map (nest 10) $ [txt 5, txt 11] )
txt :: Int -> Doc txt 0 = text "" txt k = text $ let ks = show k in (replicate (k - (length ks)) '_') ++ ks
-- * lazy variants of vcat and hcat -- you need the constructors from the HughesPJ module
vcat' = foldAbove . foldr vcomp2 empty hcat' = foldBeside . foldr hcomp2 empty
foldAbove :: Doc -> Doc foldAbove (Above Empty _ d2) = d2 foldAbove (Above d1 f d2) = Above d1 f $ foldAbove d2 foldAbove doc = doc
vcomp2 :: Doc -> Doc -> Doc vcomp2 d1 Empty = d1 -- do not match `vcomp2 Empty d1' ! vcomp2 d1 d2 = Above d1 False d2
foldBeside :: Doc -> Doc foldBeside (Beside Empty _ d2) = d2 foldBeside (Beside d1 f d2) = Beside d1 f $ foldBeside d2 foldBeside doc = doc
hcomp2 :: Doc -> Doc -> Doc hcomp2 p Empty = p hcomp2 p q = Beside p False q