如何在Haskell中使用IO创建随机列表

时间:2012-04-08 17:30:26

标签: haskell io monads

我正在尝试进行植绒模拟,以便更好地教自己haskell。在尝试生成需要随机性的模拟的初始状态时,我遇到了麻烦。我正在尝试生成一个Boids列表,它们都有随机的初始位置和方向。

在main函数中,我使用

调用它
let numBoids = 10
rBoids <- randomBoids numBoids

并且rBoids我会在IORef中存储,然后我可以更新每一帧,我认为这是正确的做事方式吗?

这是失败的代码:

-- 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)

实际失败的是return b : bs。如果我将其更改为return [b],则会编译。给出的错误是:

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 }

我迷失在这里,而且我对整个命令式功能语言(和monad)的理解至少可以说是不稳定的。任何帮助都将非常感激!

3 个答案:

答案 0 :(得分:8)

Gangadahr是对的。我只想提一下你可以缩短你的代码很多:

import Control.Applicative
import Control.Monad

randomBoids n = replicateM n randomBoid

randomBoid = Boid <$> randomVector <*> randomVector

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

第一个函数利用replicateM,当你想重复一个monadic动作并收集结果时,这是一个非常有用的函数。后两个函数使用Applicative样式,这非常有用。

答案 1 :(得分:6)

您收到错误的原因是return b : bs会使编译器将其解释为(return b): bs要解决此问题,您可以将语句更改为return (b:bs)。这将使语句返回IO[Boid]

答案 2 :(得分:4)

类型检查员正在return x : xs读取(return x) : xs。如果你写return (x:xs),那就会出现问题。