我正在尝试进行植绒模拟,以便更好地教自己haskell.在尝试生成需要随机性的模拟的初始状态时,我遇到了麻烦.我正在尝试生成一个Boids列表,它们都有随机的初始位置和方向.
在主要功能中,我称之为使用
let numBoids = 10
rBoids <- randomBoids numBoids
Run Code Online (Sandbox Code Playgroud)
而rBoids我indend在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)
Run Code Online (Sandbox Code Playgroud)
实际上失败的是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 }
Run Code Online (Sandbox Code Playgroud)
我在这里迷失了,而且我对整个命令式功能语言(和monad)的理解至少可以说是不稳定的.非常感激任何的帮助!
Gangadahr是对的.我只想提一下你可以缩短你的代码很多:
import Control.Applicative
import Control.Monad
randomBoids n = replicateM n randomBoid
randomBoid = Boid <$> randomVector <*> randomVector
randomVector = Vector2 <$> randomRIO (-1, 1) <*> randomRIO (-1, 1)
Run Code Online (Sandbox Code Playgroud)
第一个函数利用了replicateM,当你想重复monadic动作并收集结果时,这是一个非常有用的功能.后两个函数使用Applicative样式,这非常有用.
您收到错误的原因是因为return b : bs将使编译器将其解释(return b): bs为解决此问题,您可以将语句更改为return (b:bs).这将使声明返回IO[Boid]