[Haskell-cafe] Re: Knot tying vs monads

John D. Ramsdell ramsdell0 at gmail.com
Sat Nov 17 13:30:56 EST 2007


Thank you for your interesting reply.  I found it enlightening.

Compared to that, I'm missing the specification part for your pretty
> printer. How's it supposed to lay out?


The specification is in Paulson's book.  The pretty printer is used with
S-Expressions, and the block layout generates compact, indented output that
is good when there is much data to be displayed.  I played around with the
Hughes pretty printer, but it wasn't obvious how to get the output I knew I
could from the Paulson pretty printer.  I confess I did not spend much time
tinkering with the Hughes pretty printer.

I failed to mention in my original note that the code was written so that
the Haskell version lines up with the Standard ML version.  The close
connection between the Haskell and Standard ML versions is part of the
reason I was able to quickly generate the code, and be confident in its
correctness.  It also explains why I did not use the sum function in the
Prelude, or your map trick when writing the blo function.

> What style do to you prefer, a knot-tying or a monad-based style?  I
> have enclosed the pretty printer.  The printing function is the
> subject of the controversy.

... a simple difference list ... will do.


Hmm.  Doesn't the output type (Int, String) -> (Int, String) show the
implementation is using the essence of a difference list?  Remember, the
resulting function prepends something the string it is given in the second
element of the pair, and returns that string.

Introducing a difference list means to replace the output type
>
>   (Int, String) -> (Int, String)
>
> of  printing  by
>
>   Int -> (Int, String -> String)   -- difference list
>

My first attempt at writing the printing function had a type similar to this
one.  I found myself composing difference lists of type ShowS.  The
performance was noticabily slow, specially as compared with the
implementation displayed in my message.  Perhaps the use of Data.DList would
repair this performance problem.

I don't mean to suggest that ShowS style difference lists cannot be used to
make the function easier to understand--all I'm saying is my attempt to do
so did not work out well.

>> module Pretty(Pretty, pr, blo, str, brk) where
>
>> data Pretty
>>     = Str !String
>>     | Brk !Int              -- Int is the number of breakable spaces
>>     | Blo ![Pretty] !Int !Int -- First int is the indent, second int
>>     --  is the number of chars and spaces for strings and breaks in block

Drop those strictness annotations from !String and ![Pretty], they won't
> do any good. The !Int are only useful if they will be unboxed, but I
> wouldn't bother right now.


I thought that the annotations ensure the first element of the list is
evaluated.  The Char and Pretty lists are generated with seqrev, so
everything gets evaluated before constructor is applied to data.

-- A reverse that evaluates the list elements.
seqrev :: [a] -> [a]
seqrev = foldl (\xs x -> x `seq` xs `seq` (x:xs)) []

The trouble is the constructors are not exported directly, but instead
through str, brk, and blo, functions which are not strict.  It's the best I
could do, as near as I can tell.

It seems rather hard to avoid lazyness in the current version of Haskell
when it's not wanted.  I hope one of the proposals for deep strictness makes
it into Haskell prime.  In my application, there is one datastructure, such
that if every value tracable from an instance of the datastructure is
evaluated, I am quite sure my program will be free from memory leaks due to
dragging.  I wish I could tell compilers to make it so.

John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20071117/51d21c20/attachment.htm


More information about the Haskell-Cafe mailing list