Tags:

I think you were missing a 'do' in the 'then' part of your for loop implementation.

Also, may we use this as an exercise in the wikibook?
if you put a do after the then you can write it like you get rid of the cryptic error messages:

Oh, I haven't got around to setting a CC license, but yes, in general this blog would be Attribution-ShareAlike, does that work for the wikibook?

Hmm, my comment got the last part deleted, it sould be:

If you put a do after the then. You can write it like this to get rid of the cryptic error messages:

for i p pp f =

do if p i

then do

(f i)

for (pp i) p pp f

else

return ()

Thanks! I ended up putting a block of exercises in the chapter on higher order functions. Your comments would certainly be welcome. Note that to reduce the spoilertude, I put link to your blog on the solutions page only.
I can't tell from the text whether or not you're aware, but the typical way to write this would be:
flip mapM_ [1..10] \$ \x -
Let me try again. If this doesn't work, i give up:
flip mapM_ [1..10] \$ \x -&gt putStrLn \$ show x
[this is good]
This also works:

for i p pp f =
if p i
then
(f i) >> for (pp i) p pp f
else
return ()

Like Andrew said, for your typical loop through a range of numbers just use 'flip mapM_'. It's useful enough that some people give it the name 'forM_'. Having said that it's more of a foreach loop rather than a more general for loop.

Another approach is to realise that for loops can be expressed using while loops. So you take the 'until' function and make that monadic:

untilM :: Monad m => (a -> m Bool) -> (a -> m a) ->a -> m a
untilM p f x = do
b <- p x
if b then return x
else do { x' <- f x; untilM p x' f }

(Note that it's (a -> m Bool) rather than (a -> Bool) - you have to do this to follow the M-suffix naming convention correctly, and besides, it lets us make side-effecting tests if we need to. If you want a pure test, just use 'return' to take it into the monad.) Then you naturally get a 'while' loop like so:

whileM :: Monad m => (a -> m Bool) -> (a -> m a) -> a -> m a
whileM p f x = forM (liftM not . p) f x

for i p pp f = whileM (return . p) (\n -> do {f x; return (pp x)}) i >> return ()

Which has the advantage from a performance point of view of not creating and then destroying a list.
Hmm, I should have used braces in the do block in 'untilM' - as it is the layout is screwed up. Oh well, it should be clear enough.
Typo: (\n -> do { .. }) should be (\x -> do { .. }) of course.
Yeah, I think I'd use the mapM_ things in general, but was just playing :-)

The suggestion about whileM, and the datastructure creation and destruction is interesting, and is something I don't yet understand deeply enough to reason about! Thanks for the pointer.