
Benedikt Despite the name, neither I nor John Hughes are actively maintaining this library, so if you have got some better implementations of 'cat' and 'sep', do please submit a patch. That's how it'll improve. Do test carefully! Preferably add some Quickcheck tests too. Thanks Simon | -----Original Message----- | From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe- | bounces@haskell.org] On Behalf Of Benedikt Huber | Sent: 19 June 2008 13:31 | To: Evan Laforge | Cc: haskell | Subject: [Haskell-cafe] Re: Meaning of "ribbonsPerLine" at | Text.PrettyPrint.HughesPJ ? | | 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 | | _______________________________________________ | Haskell-Cafe mailing list | Haskell-Cafe@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-cafe