2016-10-18 2 views
3

В проблеме моделирования мне нужно создать тысячи объектов-агентов, которые ведут себя независимо друг от друга. Для этого мне нужно передать каждому из этих агентов другой генератор случайных чисел. Как это сделать в Haskell? На языке, таком как C, я могу просто генерировать случайное число всякий раз, когда это необходимо, но в Haskell мне нужно сделать это только в монаде IO. Поведение агентов в полностью чистом вычислении.Haskell как генерировать бесконечное количество списков бесконечных случайных чисел для моделирования?

Я делаю это следующим образом в настоящее время:

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 монаде не может просто отобразить функцию в списке. Есть ли лучший и более похожий на 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>> 
+3

Ваш путь совершенно прав - ваша функция принимает бесконечный список в качестве аргумента и фактически генерирует список в 'main'. Кроме того, бесконечный список 'Int' и бесконечный список бесконечных списков' Int' содержат одинаковое количество элементов. Вы продемонстрировали, что у вас нет бесконечного числа агентов, поэтому почему бы не иметь конечное число случайных списков: 'map (agentRun args. Randoms) <$> replicateM numRuns newStdGen'. Наконец, если вы имеете дело со случайностью, вы можете воспользоваться [некоторой абстракцией] (https://hackage.haskell.org/package/MonadRandom-0.4.2.3). – user2407038

+1

'Data.List.unfoldr (Just. Split) :: RandomGen b => b -> [b]' дает вам бесконечный список генераторов, учитывая один. Если ваша функция имеет такое ограничение, она может использовать бесконечные списки бесконечных списков 'Int'. Я не знаю, так ли это иррационально. – Michael

+1

Обратите внимание, что 'System.Random' - очень плохой генератор и может привести к плохой работе вашей программы. Рассмотрите возможность использования одного из других генераторов, таких как 'System.Random.TF' из tf-random. –

ответ

2

Вероятно, у вас есть структура, содержащих параметры агента, а также функция

agentRun :: AgentParams -> [Int] -> Agent 

Ваша проблема в том, как создать бесконечный список Ints для каждого агента.

Предположительно вы начинаете со списком AgentParams, и вы хотите отобразить agentRun над ним, как это:

agentsParams :: [AgentParams] 
agents = map (\p -> agentRun p ????) agentParams 

Беда в том, вы не можете увидеть, как получить другой бесконечный список в каждый агент.

Для этого используются функции библиотеки unfoldr и split:

unfoldr :: (b -> Maybe (a, b)) -> b -> [a] 
split :: (RandomGen g) => g -> (g,g) 

unfoldr возит на применении его функции, пока не вернется Nothing.

split принимает случайный генератор и возвращает два новых. Итак, Just . split делает хороший аргумент для unfoldr.

infiniteGenerators :: (RandomGen g) => g -> [g] 
infiniteGenerators = unfoldr (Just . split) 

Теперь вы можете отобразить этот бесконечный список генераторов в бесконечный список бесконечных списков:

infiniteRandomLists :: (RandomGen g) => g -> [[Int]] 
infininteRandomLists = map randoms . infiniteGenerators 

Затем вы можете использовать zipWith, чтобы получить список агентов:

agents gen = zipWith agentRun (infiniteRandomLists gen) 

Однако при кодировании ваших агентов вам, скорее всего, будет легче работать с генератором, а не с бесконечным списком Ints. Это происходит из-за общей структуры в функциях этого вида, где вы пишете:

(gen2, gen3) = split gen1 
result = foo gen2 

Это позволяет Вам экономить пройти обновленный генератор обратно из foo.Если вы принимаете номера из бесконечного списка, то вам придется сделать что-то вроде:

(randomList2, result) = foo randomList1 

Но лучшим решением было бы использовать какой-то случайной состояния монады для управления все это для вас.

+0

Отличный ответ. Помог мне узнать о генераторах. – mntk123

+0

Haskell продолжает удивлять меня - все приятные сюрпризы. Эта проблема была вне меня, и я подумал: лучшего решения нет. Но этот маленький трюк «раскола» генератора заставил меня остерегаться. – mntk123

Смежные вопросы