[Haskell-cafe] Re: How to pretty print code efficiently

2009-07-03 Thread Achim Schneider
John Ky newho...@gmail.com wrote:

 Hi,
 
 Currently I'm pretty printing code by building arrays of strings and
 calling indent.  For example:
 
 instance JavaPrintableNamed AST.EnumeratedType where
javaLinesNamed parentName (AST.EnumeratedType memberDefinitions) =
   [ public enum  ++ asJavaId(parentName)
   , {
   ] ++ memberCodeLines ++
   [ }
   , 
   ]
   where
  memberCodeLines = indent $ javaLines memberDefinitions
 
 The indent function takes a list of strings and adds an indent to the
 beginning of every line.
 
 I can imagine this to be very inefficient as it builds many strings
 and concatenates them.
 
Yes and no. When concatenating two lists, only the first one is
rebuild, the second one is reused, due to sharing. So if you
concatenate short strings to the front of a long string you're quite
fine. But then, that isn't the answer you hoped for.

 In Ruby, I might do the same thing like this:
 
 class EnumeratedType  JavaPrintableNamed
def writeTo(writer)
   writer.print public enum 
   writer.puts self.asJavaId
   writer.puts {
   writer.indent do
  self.memberDefinitions.writeTo(writer)
  writer.puts
   end
 
 where above, the writer.indent takes care of the indent, and
 everything is appended to a stream, which doesn't seem so bad in
 terms of efficiency.
 
 I'm looking for a way to do something similar in Haskell.
 
 Anyone can give me a hand?
 
As data structure use Data.ByteString.Lazy: concatenating two lazy
bytestrings doesn't involve rebuilding the first string byte-by-byte,
but constructs a superstructure denoting the concatenation.

As for how to express it in code: I'd recommend a combination of a State
monad to track the indentation, and the underused[1] Applicative
interpretation of lists to concatenate stuff. = would function as
concatenation of lines, getting the state, while the indent function
would first set it to the new level, then execute the passed
sub-action, and finally reset it to the old level. You're going to need
a way to concatenate two strings without doing a line-break, too, of
course.

All in all, it's a splendid exercise in how to write custom monads.


[1] Lists as ordered collections, not possibilities, that is, see e.g.
the typeclassopedia 
( http://www.haskell.org/sitewiki/images/8/85/TMR-Issue13.pdf )

-- 
(c) this sig last receiving data processing entity. Inspect headers
for copyright history. All rights reserved. Copying, hiring, renting,
performance and/or quoting of this signature prohibited.


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: How to pretty print code efficiently

2009-07-03 Thread Achim Schneider
Achim Schneider bars...@web.de wrote:

 As for how to express it in code: I'd recommend a combination of a
 State monad to track the indentation, and the underused[1] Applicative
 interpretation of lists to concatenate stuff. = would function as
 concatenation of lines, getting the state, while the indent function
 would first set it to the new level, then execute the passed
 sub-action, and finally reset it to the old level. You're going to
 need a way to concatenate two strings without doing a line-break,
 too, of course.

Make that Reader Monad and execute the passed sub-action with the
new level inside a new monad

-- 
(c) this sig last receiving data processing entity. Inspect headers
for copyright history. All rights reserved. Copying, hiring, renting,
performance and/or quoting of this signature prohibited.


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe