
Hi All, I just wrote a function to repeatedly transform something inside a monad using the same transforming function every time. I feel it might be dodgy though: iterateM :: (Monad m) => (a -> m a) -> m a -> m [a] iterateM f sm = sm >>= \s -> iterateM f (f s) >>= \ss -> return (s:ss) The context is that I was trying to write a state machine that responded to keyboard input: data Event = LoYes | LoNo | LoNum -- buttons on your phone | ReYes | ReNo | ReNum -- buttons on his phone data State = State { handler :: Event -> IO State } main = hSetBuffering stdin NoBuffering >> -- so you don't have to hit return iterateM (\st -> getEvent >>= handler st) (return idle) getEvent :: IO Event getEvent = getChar >>= \c -> case c of 'y' -> return LoYes 'n' -> return LoNo '0' -> return LoNum 'Y' -> return ReYes 'N' -> return ReNo '1' -> return ReNum _ -> getEvent idle, ringing, waiting, talking :: State idle = State $ \e -> case e of LoYes -> return idle LoNo -> return idle LoNum -> putStrLn "\tCalling somebody" >> return waiting ReYes -> return idle ReNo -> return idle ReNum -> putStrLn "\tIt's for you-hoo" >> return ringing -- other states similar The reason I'm worried is that this is the second time I've needed such a thing and it seems odd that it's not in the prelude already. Does it leak memory? Does it have a tail recursion problem? Is the functionality I want covered by something else? I guess I could consider [a] to be b in a regular monad but then the (\st -> getEvent >>= handler st) bit would have to juggle lists which seems meaningless. Am I missing something or does everybody else have this iterateM in their personal prelude? TIA, Adrian.

I would use the State monad rather than passing the state explicitly. Then the "body of the loop" is of type "m a" rather than "a -> m a", and you can use "sequence . repeat" on it. -Karl

Hi Volker,
In the meantime I did something very simple. I just have a step function
taking a maybe state parameter which recurses until the state is nothing.
Then main = step init
Adrian.
On 18 Jun 2013 13:29, "Karl Voelker"
I would use the State monad rather than passing the state explicitly. Then the "body of the loop" is of type "m a" rather than "a -> m a", and you can use "sequence . repeat" on it.
-Karl
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

`iterateM_` is in the monad-loops package[1]. Like you suggested, this version returns `m b` and doesn't build up any list at all. You can search for functions by name and even type signature on Hackage[2] or Hayoo[3]. On a different note, for code such as your `iterateM` you should use do-notation instead of manually writing out the lambdas. It's much easier on the eyes and this is what do-notation is there for. [1] http://hackage.haskell.org/packages/archive/monad-loops/latest/doc/html/Cont... [2] http://www.haskell.org/hoogle/ [3] http://holumbus.fh-wedel.de/hayoo/hayoo.html
participants (3)
-
Adrian May
-
Karl Voelker
-
Lukas Braun