I have some functions written in C that I call from Haskell. These functions return IO (CInt). Sometimes I want to run all of the functions regardless of what
Edit: Now I see what you're looking for.
gbacon posted a nice sequenceWhile function, which is almost the "primitive" you need.
Actually, since you're only interested in the side effects, sequenceWhile_ should be enough. Here's a definition (again, inspired by gbacon, vote him up!):
sequenceWhile_ :: (Monad m) => (a -> Bool) -> [m a] -> m ()
sequenceWhile_ p xs = foldr (\mx my -> mx >>= \x -> when (p x) my)
(return ()) xs
You call this like so:
Prelude Control.Monad> sequenceWhile (<4) $ map f [1..]
Original answer:
You can't just "unlift" the values from the IO Monad for use with takeWile, but you can "lift" takeWhile for use within a Monad!
The liftM function will take a function (a -> b) to a function (m a -> m b), where m is a Monad.
(As a side note, you can find a function like this by searching for its type on Hoogle, in this case by searching for: Monad m => (a -> b) -> (m a -> m b))
With liftM you can do this:
Prelude> :m + Control.Monad
Prelude Control.Monad> let f x = print x >> return x
Prelude Control.Monad> liftM (takeWhile (<4)) $ mapM f [0..5]
0
1
2
3
4
5
[0,1,2,3]
Now, this might not be what you wanted. The mapM will apply the f function to the entire list in sequence, before returning a list. That resulting list is then passed to the lifted takeWhile function.
If you want to stop printing after the third element, you'll have to stop calling print. That means, don't apply f to such an element. So, you'll end up with something simple like:
Prelude> mapM_ f (takeWhile (<4) [0..5])
By the way, should you wonder why mapM will first print everything, before returning the list. You can see this by replacing the functions with their definitions:
mapM f [0..1]
=
sequence (map f [0..1])
=
sequence (f 0 : map f [1..1])
=
sequence (f 0 : f 1 : [])
=
sequence ((print 0 >> return 0) : f 1 : [])
=
sequence ((print 0 >> return 0) : (print 1 >> return 1) : [])
=
do x <- (print 0 >> return 0)
xs <- (sequence ((print 1 >> return 1) : []))
return (x:xs)
=
do x <- (print 0 >> return 0)
xs <- (do y <- (print 1 >> return 1)
ys <- sequence ([])
return (y:ys))
return (x:xs)
=
do x <- (print 0 >> return 0)
xs <- (do y <- (print 1 >> return 1)
ys <- return []
return (y:ys))
return (x:xs)
=
do x <- (print 0 >> return 0)
xs <- (do y <- (print 1 >> return 1)
return (y:[]))
return (x:xs)
=
do x <- (print 0 >> return 0)
xs <- (print 1 >> return (1:[]))
return (x:xs)
=
do x <- (print 0 >> return 0)
print 1
return (x:1:[])
=
do print 0
print 1
return (0:1:[])
This process of replacing functions with their definitions is called equational reasoning.
If I didn't make any mistakes, you can now (hopefully) see that mapM (using sequence) first prints everything, and then returns a list.