
John Ky
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.