【发布时间】:2017-02-28 04:20:25
【问题描述】:
在模拟问题中,我需要生成数千个彼此独立行为的代理对象。为此,我需要为每个代理传递一个不同的随机数生成器。如何在 Haskell 中做到这一点? 在像 C 这样的语言中,我可以在需要时生成一个随机数,但在 Haskell 中,我只需要在 IO monad 中执行此操作。代理在完全纯计算中的行为。
我现在是这样做的:
import System.Random
main = do
gen1 <- newStdGen
let rands1 = randoms gen :: [Int]
gen2 <- newStdGen
let rands2 = randoms gen :: [Int]
let sout = map (agentRun extraArgs) [rands1,rands2]
writeFile "output" $ unlines sout
agentRun = <<some pure code that uses random numbers>>
下面给出了我可以解决这个问题的一种方法,但它的缺点是它只需要在 IO monad 中运行,而且我不能只将函数映射到列表上。有没有更好、更像 Haskell 的方法来做到这一点?如果是,请给出示例代码示例。
请注意,代理需要访问无限列表,因为事先不知道需要多少随机数。
import System.Random
main = do
dorun 10
dorun 0 = return ()
dorun n = do
gen1 <- newStdGen
let rands1 = randoms gen :: [Int]
let sout = agentRun extraArgs rands1
appendFile "output" sout
dorun (n-1)
agentRun = <<some pure code that uses random numbers>>
【问题讨论】:
-
你的方法是完全正确的——让你的函数将一个无限列表作为参数,并在
main中实际生成列表。此外,Int的无限列表和Int的无限列表包含相同数量的元素。您已经证明您没有无限数量的代理,那么为什么没有有限数量的随机列表:map (agentRun args . randoms) <$> replicateM numRuns newStdGen。最后,如果您经常处理随机性,您可能会受益于some abstraction。 -
Data.List.unfoldr (Just . split) :: RandomGen b => b -> [b]给你一个无限的生成器列表,给定一个。如果您的函数有这样的约束,它可以使用无限列表的无限列表Ints 。我不知道这是否不合理。 -
请注意,
System.Random是一个非常糟糕的生成器,可能会导致您的程序行为不佳。考虑使用其他生成器之一,例如来自 tf-random 的System.Random.TF。 -
你可以让你的函数在
Randmonad 中工作... -
@user2407038 我知道 Int 的无限列表和 Int 的无限列表的无限列表包含相同数量的元素。但问题是我不能轻松(有效地)将这些传递给不同的代理。
标签: haskell random simulation infinite