2012-02-15 3 views
0

MonadRandomを使用しようとしています。私はそれをrandomPrefの機能に入れましたが、それ以降はすべてが拾い読みされます!任意のヒントが評価されます。モナドランダムを使用するコードをリファクタリングする方法

module AgentGenerator where 

import System.Random 
import Data.Hashable 
import Control.Monad.Random 

import System.Environment 

-- Generate agents and write to a file 
-- 'fname' - output filename 
-- 's' - number of agent sets 
-- 'n' - number of agents in a set 
-- 'x' - number of preferences per agent 
generate fname s n x = do 
    writeFile fname $ show $ generateAgentSets s n x 

-- Agent type: Name, List of preferences 
data Agent = Agent String [Double] deriving Show 
type AgentSet = [Agent] 

-- Generate 's' sets of 'n' agents each, with 'x' preferences each 
generateAgentSets:: Integer -> Integer -> Integer -> [AgentSet] 
generateAgentSets s n x = [generateAgents n x | i <- [1..s] ] 

-- Generate n agents with 'x' preferences each 
generateAgents:: Integer -> Integer -> AgentSet 
generateAgents n x = [createAgent (show i) x | i <- [1..n]] 

-- Create agent 'name' with 'x' preferences 
createAgent:: String -> Integer -> Agent 
createAgent name x = Agent name prefs where 
    prefs = [ randomPref (i + hashed) | i <- [1..x] ] where 
     hashed = fromIntegral (hash name) 

-- Generate single random value between [0, 1] based on the seed 
-- TODO: Get rid of the seed thing and use MonadRandom instead 
randomPref :: (RandomGen g) => Integer -> Rand g [Double] 
randomPref seed = getRandomR (0.0, 1.0) 

答えて

10

あなたは

data Agent = Agent String [Double] 

としてAgentを定義しました。しかしcreateAgentに、あなたは、別のタイプのエラーは、そのrandomPrefであるタイプ

Agent String [Rand g [Double]] 

を使用してAgentを構築しようとしていますシグネチャでは、ランダムな2倍のリストを生成していると言われていますが、1つのダブルしか生成しません。私はまた、関数がどのように動作すべきかを100%確信しているわけではありません。 Randモナドを返すか、シード値を取ってそれを使ってプレーン・ダブルを生成するかのどちらかです。両方を持つことは本当に意味をなさない。

はここでシードを使用したバージョンだ、と私はここでは例として System.Randomから mkStdGenを使用しました無地のダブル

randomPref :: Integer -> Double 
randomPref seed = evalRand (getRandomR (0.0, 1.0)) g where 
    g = mkStdGen (fromIntegral seed) 

を返しますが、あなたはRandomGenのいくつかの他のインスタンスに置き換えることをお勧めします。

しかし、上記MonadRandomのかなり疑問使用であり、それは特定の種で各エージェントを生成することが本当に重要でない限り、それは今、私たちにはないrandomPref

このような
randomPref :: RandomGen g => Rand g Double 
randomPref = getRandomR (0.0, 1.0) 

を実装するために、おそらくより論理的です種の値を取る、我々はちょうどrandomPrefがランダムな二重であると宣言します。しかし、通常のダブルのようにランダムなダブルを使うことはできないので、他の関数も変更する必要があります。まず、createAgent

createAgent:: RandomGen g => String -> Int -> Rand g Agent 
createAgent name x = Agent name <$> prefs where 
    prefs = replicateM x randomPref 

私たちは、私たちが実際にランダムAgentを返しているという事実を反映するために、署名を変更します。 <$>演算子はモジュールControl.Applicativeからのもので、平方の値がRandの値になることを期待する関数を適用するために使用されます。これはちょうどfmap (Agent name) prefsを書くためのより良い方法です。

prefsは、モナドの値をx回複製するxxxのランダムな設定を得るために、replicateM(モジュールControl.Monadから)で定義されます。別の言葉では、Integersではなく、Intの値を使用するようにすべての関数を変更しました。何十億ものエージェントを実際に生成しない限り、これによりコードが大幅に高速化され、多くの標準ライブラリ関数(replicateMなど)はマシンintだけを受け入れます。

generateAgents:: RandomGen g => Int -> Int -> Rand g AgentSet 
generateAgents n x = mapM (\i -> createAgent (show i) x) [1..n] 

generateAgentsも同様に変更されています。我々はランダムにAgentSetを返すという署名に注意し、リストの理解度をmapMに変更する。 mapMは標準map関数と似ていますが、モナド値を返す関数(例えばRand)を使用しています。

generateAgentSets:: RandomGen g => Int -> Int -> Int -> Rand g [AgentSet] 
generateAgentSets s n x = replicateM s (generateAgents n x) 

generateAgentSetsは、同じルーチンに従います。リスト内包表記をreplicateMに置き換えて、ランダムエージェントセットのインスタンスを生成しました。

最大の変化は、generate機能に必要とされる私たちは、その後、その後、書き込むことができ、プレーンAgentSet値にRand AgentSet値をオンにするevalRandで使用される乱数生成器に渡す必要があり

generate :: RandomGen g => FilePath -> Int -> Int -> Int -> g -> IO() 
generate fname s n x g = do 
    let randomSets = generateAgentSets s n x 
     agentSets = evalRand randomSets g 
    writeFile fname $ show agentSets 

ディスクに保存します。

我々はfmap/<$>と、このような代わりに、昔ながらのリスト内包のmapMreplicateMなどの機能を必要とする理由をよりよく理解を得るために、あなたはLearn you a Haskell for Great GoodからChapter 11Chapter 12を読むことをお勧めします。

+0

ありがとう、私の 'randomPref'はリストを返すべきではありません - 私はちょうどこの型シグニチャ' Rand g [Double] 'をどこかに見つけてそれを無意識に使用しました。 '' MonadRandom''を使わなかった '' seed''は古いコードのままです - 実際 '' randomPref''を除くすべては 'MonadRandom'を使わないコードです。悪い事を使う方法!混乱させて申し訳ありません。 – drozzy

+0

コンソールから 'generate" out.txt "2 10 3 getStdGen'を使用しようとすると、' RandomGen(IO StdGen) 'エラーが発生します:-( – drozzy

+0

getStdGenはモナドの値を返します。 'getStdGenは>> = 2 10 3' "out.txtを" を生成、または代替的に、あなたは2 10 3(newStdGen種)' "out.txtを" 生成する '使用することができる。差は、共有、' getStdGen'グローバルを返すことですランダムなジェネレータと 'newStdGen'はシード値に基づいて新しい乱数ジェネレータを作成します – shang

関連する問題