我正在尝试使用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)
Run Code Online (Sandbox Code Playgroud)
sha*_*ang 10
你定义Agent为
data Agent = Agent String [Double]
Run Code Online (Sandbox Code Playgroud)
但在createAgent,你正在尝试构建一个Agent使用类型
Agent String [Rand g [Double]]
Run Code Online (Sandbox Code Playgroud)
另一个类型错误是,randomPref签名表示您正在生成随机双打列表,但您只生成一个双精度数.考虑到你从不在任何地方使用种子值,我也不是100%确定函数应该如何工作.您要么返回一个Randmonad,要么取一个种子值并使用它来生成一个普通的double.两者都没有意义.
这是一个使用种子的版本,并返回一个普通的double
randomPref :: Integer -> Double
randomPref seed = evalRand (getRandomR (0.0, 1.0)) g where
g = mkStdGen (fromIntegral seed)
Run Code Online (Sandbox Code Playgroud)
我mkStdGen从System.Random这里用作例子,但你可能想用其他一些实例替换它RandomGen.
但是,以上是一个非常值得怀疑的使用,MonadRandom除非用特定的种子生成每个代理非常重要,否则实现randomPref这样可能更合乎逻辑
randomPref :: RandomGen g => Rand g Double
randomPref = getRandomR (0.0, 1.0)
Run Code Online (Sandbox Code Playgroud)
现在我们不接受种子值,我们只是声明这randomPref是一个随机的双倍.但是,你不能只使用一个随机的双倍,因为它是一个普通的双,所以我们也需要改变其他功能.第一,createAgent
createAgent:: RandomGen g => String -> Int -> Rand g Agent
createAgent name x = Agent name <$> prefs where
prefs = replicateM x randomPref
Run Code Online (Sandbox Code Playgroud)
我们更改签名以反映我们实际上返回随机的事实Agent.的<$>操作者是从模块Control.Applicative,它是用于应用功能期待一个普通值的Rand值.这只是一种更好的写作方式fmap (Agent name) prefs.
prefs是根据replicateM(来自模块Control.Monad)定义的,它复制monadic值x次,因此你得到x个随机prefs.另一方面,我已将所有函数更改为使用Int值而不是Integers.除非你真的想要生成数十亿个代理,否则这会使代码更快,许多标准库函数(例如replicateM)只接受机器整数.
generateAgents:: RandomGen g => Int -> Int -> Rand g AgentSet
generateAgents n x = mapM (\i -> createAgent (show i) x) [1..n]
Run Code Online (Sandbox Code Playgroud)
generateAgents以类似的方式改变.我们在签名中注意到我们正在返回一个随机的AgentSet,并将列表理解更改为mapM.mapM就像标准map函数一样,除了它与返回monadic值的函数(例如Rand)一起使用.
generateAgentSets:: RandomGen g => Int -> Int -> Int -> Rand g [AgentSet]
generateAgentSets s n x = replicateM s (generateAgents n x)
Run Code Online (Sandbox Code Playgroud)
generateAgentSets遵循相同的程序.我们已经用列表推导替换了replicateM生成随机代理集的s实例.
generate功能中需要进行最大的更改
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
Run Code Online (Sandbox Code Playgroud)
我们需要传入一个随机数生成器,然后将其evalRand用于将Rand AgentSet值转换为普通AgentSet值,然后将其写入磁盘.
为了更好地理解为什么我们需要fmap/ <$>和,如功能mapM和replicateM平原老以列表解析,你可能需要阅读第11和第12章从了解你的Haskell的极大的利好.