[Haskell-beginners] Recursion in monad

Chaddaï Fouché chaddai.fouche at gmail.com
Tue Mar 22 21:44:20 CET 2011


On Tue, Mar 22, 2011 at 5:46 AM, Adrian May
<adrian.alexander.may at gmail.com> wrote:
> OK I did this:
>
> import System.Random
>
> walk :: Int -> IO Int
> walk i = randomRIO (0,1) >>= \r -> return (i+r*2-1)
>
> say :: Int -> IO ()
> say i = putStrLn $ show i
>
> rep :: Int -> a -> (a -> IO a) -> (a -> IO ()) -> IO ()
> rep n i w s
>       | n<=0 = return ()
>       | otherwise = s i >> w i >>= \ii -> rep (n-1) ii w s
>
> main :: IO ()
> main = rep 10 50 walk say
>
> Is that the easiest way?

I don't know about "easiest", it's not bad though there are thing that
can be improved

> say i = putStrLn $ show i

This already exist and is called "print" (though its type is more
general than your signature).

> walk i = randomRIO (0,1) >>= \r -> return (i+r*2-1)

The >>= ... return is pretty ugly, it would rather be written as :

> walk i = fmap (\r -> i + r * 2 - 1) $ randomRIO (0,1)

> rep n i w s

Passing say and walk as parameter seems a bit overkill, I seriously
doubt that you'll ever need this exact structure again, and even then
passing a single action should be enough :

> rep n act i
>   | n <= 0 = return ()
>   | otherwise = act i >>= \x -> rep (n-1) act x

rep may also be written with standard monad operations :
> rep n act i = foldM (\x _  -> act x) i $ replicate (n-1) ()

Lastly it may be that the structure of the program itself,
particularly the use of randomRIO is suboptimal and a bit ugly, for a
throwaway program I would probably just use randomRs :

> main = do
>   g <- newStdGen
>   mapM_ print . tail . scanl (\i r -> i+r*2-1) 50 . take 10 $ randomRs (0,1) g

but for a more complex endeavour I would rather use a serious library
like mwc-random. (System.Random performances are awful)

-- 
Jedaï



More information about the Beginners mailing list