4

私は自分自身にhaskellをよりよく教えるために、群れのシミュレーションをしようとしています。ランダム性を必要とするシミュレーションの初期状態を生成しようとすると、問題が発生します。すべてランダムな初期位置と方向を持つボイドのリストを生成しようとしています。

メイン関数では、これを使用して呼び出します

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 }

私はここでかなり迷っています。関数型言語(およびモナド)の命令型コード全体についての私の理解は控えめに言っても不安定です。どんな助けでも大歓迎です!

4

3 に答える 3

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、を利用します。これは、モナディックアクションを繰り返して結果を収集する場合に非常に便利な関数です。後者の2つの関数Applicativeは、非常に便利なスタイルを使用します。

于 2012-04-08T22:29:36.950 に答える
6

エラーが発生する理由return b : bsは、コンパイラがエラーを次のように解釈するためです。(return b): bsこれを修正するには、ステートメントをに変更しreturn (b:bs)ます。これにより、ステートメントはIO[Boid]

于 2012-04-08T17:51:04.917 に答える
4

タイプチェッカーはとして読み取っreturn x : xsてい(return x) : xsます。あなたが書くならば、return (x:xs)それはタイプチェックします。

于 2012-04-08T17:46:28.887 に答える