我正在尝试进行植绒模拟,以便更好地教自己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)的理解至少可以说是不稳定的。任何帮助都将非常感激!
答案 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)
,那就会出现问题。