Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating a List of random Integers with condition in Haskell

Tags:

haskell

Here I am trying to generate a list of Integers where I want to add random numbers to the list while the condition where md<=1 is not satisfied. I tried several times but with no luck.

fx :: Int -> Int -> IO [Int]
fx md s = do
  x <- randomRIO (1,min md s)
  if md<=1
     then return [md]
     else return md:(fx (md-x) s)
like image 882
Akshay Hazari Avatar asked Mar 27 '15 08:03

Akshay Hazari


1 Answers

The error is at the last line:

else return md:(fx (md-x) s)

The result of fx is in the IO monad, and with that result you want to perform a pure operation of prepending md to it. This is exactly what liftM does, your last line should be

else liftM (md :) (fx (md-x) s)

Other small improvements:

  • You don't really need IO, you only need to generate random numbers within the function. For this you could use the MonadRandom type class (residing in the package with the same name). This will make the function more specific, type-safe and flexible.
  • It's redundant to generate a random number and only after then check if you need it - the comparison md <= 1 doesn't need x at all.

So an improved version might look like:

import Control.Monad
import Control.Monad.Random

fx :: (MonadRandom m) => Int -> Int -> m [Int]
fx md s | md <= 1   = return [md]
        | otherwise = do
              x <- getRandomR (1, min md s)
              liftM (md :) (fx (md-x) s)

alternative without liftM

maybe this is easier to understand:

fx :: (MonadRandom m) => Int -> Int -> m [Int]
fx md s | md <= 1   = return [md]
        | otherwise = do
              x  <- getRandomR (1, min md s)
              xs <- fx (md-x) s
              return (md : xs)
like image 157
Petr Avatar answered Oct 05 '22 23:10

Petr