Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a random list using IO in Haskell

Tags:

io

haskell

monads

I'm trying to do a flocking simulation in order to better teach myself haskell. I'm running into trouble when trying to generate the initial state for the simulation which requires randomness. I'm trying to generate a list of Boids which all have random initial positions and directions.

In the main function I call this using

let numBoids = 10
rBoids <- randomBoids numBoids

And rBoids I indend to store in an IORef which I can then update every frame, which I think is the right way to do things?

And here is the code which fails:

-- Type for the flocking algorithm
data Boid = Boid {
    boidPosition  :: Vector2(GLfloat)
  , boidDirection :: Vector2(GLfloat)
  } deriving Show

randomBoids :: Int -> IO ([Boid])
randomBoids 0 = do
  return []
randomBoids n = do
  b <- randomBoid 
  bs <- (randomBoids (n-1))
  return b : bs

randomBoid = do
  pos <- randomVector
  vel <- randomVector
  return (Boid pos vel)

randomVector = do
  x <- randomRIO(-1.0, 1.0)
  y <- randomRIO(-1.0, 1.0)
  return (Vector2 x y)

What actually fails is return b : bs. If I change this into return [b] it compiles. The error given is:

Couldn't match expected type `IO [Boid]' with actual type `[a0]'
In the expression: return b : bs
In the expression:
  do { b <- randomBoid;
       bs <- (randomBoids (n - 1));
         return b : bs }
In an equation for `randomBoids':
    randomBoids n
      = do { b <- randomBoid;
             bs <- (randomBoids (n - 1));
               return b : bs }

I'm pretty lost here, and my understanding of the whole imperative-code-in-a-functional language (and monads) is shaky to say the least. Any help would be most appreciated!

like image 666
Dervall Avatar asked Dec 01 '22 23:12

Dervall


1 Answers

Gangadahr is correct. I only wanted to mention that you can shorten your code a LOT:

import Control.Applicative
import Control.Monad

randomBoids n = replicateM n randomBoid

randomBoid = Boid <$> randomVector <*> randomVector

randomVector = Vector2 <$> randomRIO (-1, 1) <*> randomRIO (-1, 1)

The first function takes advantage of replicateM, which is a very useful function when you want to repeat a monadic action and collect the results. The latter two functions use Applicative style, which is enormously useful.

like image 146
Gabriella Gonzalez Avatar answered Dec 14 '22 23:12

Gabriella Gonzalez