newbie "concatenating" monad question

Hi I'm new here and this is my first mail to the list, so be gentle :) I have some functions that build big strings by calling other functions and appending the result, like buildStuff = func1 ++ func2 ++ func3 ++ func4 My idea is to have a monad with a concatenating >>, so that I can: bulidStuff = do func1 func2 func3 func4 I am thinking about using the writer monad, but I would still have to use "tell". The list monad is not an option either, as it does not concatenate. Is there a proper way of doing something like this (efficiently) ? Leandro Penz

My idea is to have a monad with a concatenating >>, so that I can:
bulidStuff = do func1 func2 func3 func4
Leandro Penz
I actually did this recently for a project I have been working on. First, an example:
output label a@(I.Add a1 a2 a3) = do comment (show a) mov' label eax a1 add eax a2 mov a3 eax
My monad in this example has a Writer or a WriterT in it somewhere. I of course had to include the 'tell' that you mention somewhere, but I hid it in the 'comment', 'mov', and 'add' functions in an attempt to make my own personal assembly DSL. Obviously, you would have to either include 'tell' in your func1, func2, etc., or create wrappers for them that include a 'tell'. Just my two cents. Bryan

Leandro Penz wrote:
I have some functions that build big strings by calling other functions and appending the result, like
buildStuff = func1 ++ func2 ++ func3 ++ func4 The usual idiom is something like
buildStuff = concat [func1, func2, func3, func4] Put the list elements on separate lines if it makes life easier.
My idea is to have a monad with a concatenating >>, so that I can:
bulidStuff = do func1 func2 func3 func4
I am thinking about using the writer monad, but I would still have to use "tell". The list monad is not an option either, as it does not concatenate.
Is there a proper way of doing something like this (efficiently) ? The writer monad is a more complicated way of doing this, and might be appropriate if you want to build up a string over a lot of different functions. But its probably easier to use concat.
One thing: beware of the copying overhead. The naive use of the Writer monad is to use ++, but every time you "tell" it a new string the accumulated string so far gets copied to have the new one appended. The way around this is to use StringS (which you will find in the Prelude). StringS has the type "String -> String", which seems really wierd. An StringS takes a string, prepends something on to it, and then returns the resulting string. The clever thing is that you can take two StringS and concatenate them using (.) function composition in constant time. So I can write: foo, bar, stop, foobar :: StringS foo = ("Hello " ++) -- A function from a string to a string. bar = ("world" ++) stop = ('.' :) -- Also a function from a string to a string: work it out. foobar = foo . bar . stop -- Function composition: very efficient. main = do putStrLn (foobar "") -- Get the final result by applying the function to an empty string. You can do this inside the Writer monad as well because functions, like strings, are instances of the Monoid class (i.e. they implement mplus in the way you would expect). You just have to wrap a function around "tell" like say str = tell (str ++) and remember that runWriter will then hand you a StringS. Hope this helps, Paul.

On Sat, Mar 24, 2007 at 08:05:25PM +0000, Paul Johnson wrote:
strings, are instances of the Monoid class (i.e. they implement mplus in the way you would expect). You just have to wrap a function around
Actually they don't. stefan@stefans:/tmp$ ghc-6.4.2 -v0 -e 'main' X.hs ABend stefan@stefans:/tmp$ ghc-6.6 -v0 -e 'main' X.hs AendBend stefan@stefans:/tmp$ cat X.hs import Data.Monoid main = putStrLn $ (str1 `mappend` str2) "end" str1 = ("A" ++) str2 = ("B" ++) stefan@stefans:/tmp$ Stefan

Stefan O'Rear wrote:
On Sat, Mar 24, 2007 at 08:05:25PM +0000, Paul Johnson wrote:
strings, are instances of the Monoid class (i.e. they implement mplus in the way you would expect). You just have to wrap a function around
Actually they don't.
stefan@stefans:/tmp$ ghc-6.4.2 -v0 -e 'main' X.hs ABend stefan@stefans:/tmp$ ghc-6.6 -v0 -e 'main' X.hs AendBend stefan@stefans:/tmp$ cat X.hs import Data.Monoid main = putStrLn $ (str1 `mappend` str2) "end" str1 = ("A" ++) str2 = ("B" ++)
Does this mean that the semantics have changed? If so, which one is correct? Paul

Leandro Penz wrote:
buildStuff = func1 ++ func2 ++ func3 ++ func4
My idea is to have a monad with a concatenating >>, so that I can:
bulidStuff = do func1 func2 func3 func4
buildStuff = concat [ func1, func2, func3, func4 ] Remember, functional programming was already useful without monads. -Udo -- "It is the mark of an educated mind to be able to entertain a thought without accepting it." -- Aristotle
participants (6)
-
Bryan Burgers
-
Bryan O'Sullivan
-
Leandro Penz
-
Paul Johnson
-
Stefan O'Rear
-
Udo Stenzel