Печать значений x randomIO из списка randomIO - PullRequest
0 голосов
/ 20 октября 2011

Мне дали этот фрагмент кода, и я должен объяснить, что он не завершен, и предложить возможное исправление.

randomW =  do randomvalues <- sequence (repeat (randomIO :: IO Float))
              print (take 10 randomvalues)

Условием исправления является создание бесконечного списка, чтобы мы могли использовать функцию take.

Я думаю, что проблема связана с не слишком ленивым характером функции последовательности, которая пытается достичь конца списка, сгенерированного repeat (randomIO :: IO Float), что приводит к не завершению.

Я также не уверен, возможна ли функция повтора на randomIO.

test = do random <- repeat (randomIO :: IO Float)
          print random

Что приводит к ошибке типа. Кажется, что print не в состоянии обработать IO Float, что, по-видимому, предполагает использование повтора для типа IO Float.

Ответы [ 2 ]

2 голосов
/ 20 октября 2011

Итак:

repeat :: a -> [a]
randomIO :: Random a => IO a
sequence :: Monad m => [m a] -> m [a]

=>

repeat (randomIO :: IO Float) :: [IO Float]

Итак, когда вы делаете:

random <- repeat (randomIO :: IO Float)

Вы на самом деле используете монаду списка здесь, поэтому random имеет тип IO Float. Поскольку вы находитесь в монаде списка, ваш последний оператор должен иметь тип [a], но он имеет тип IO (), поскольку это вызов print, следовательно, ошибка типа.

Весь смысл последовательности состоит в том, чтобы преобразовать [IO a] в IO [a], который можно выполнить, чтобы получить список случайных значений, и, надеюсь, напечатать этот список. Теперь, когда вы выполняете ввод-вывод, подобный этому, его нужно выполнять все сразу, кроме случаев использования unsafeInterleaveIO, что в данном случае не рекомендуется. Поэтому он пытается получить этот бесконечный список ... и зависает (в какой-то момент это может привести к переполнению стека, я не уверен).

Чтобы получить бесконечный список случайных значений, вам все это не нужно, просто для получения случайного начального числа и вычисления случайных значений исключительно из начального числа.

Вы должны быть в состоянии составить бесконечный список случайных значений, используя эти функции :

randomIO :: Random a => IO a        -- to provide an IO Int
mkStdGen :: Int -> StdGen           -- to obtain a random generator from that Int
randoms :: RandomGen g => g -> [a]  -- to generate the infinite list

Обратите внимание, что последние две функции чистые. Чтение этой темы может дать вам больше идей.


EDIT:

Пример использования mkStdGen:

randomList :: Random a => IO [a]
randomList = do seed <- randomIO
                let gen = mkStdGen seed
                return (randoms gen)

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

Для вашего другого вопроса:

map :: (a -> b) -> [a] -> [b]
print :: Show a => a -> IO ()

=> печать карты :: Показать a => [a] -> [IO ()]

Это, вероятно, не то, что вы хотите, верно? Если вы просто хотите напечатать список, нет необходимости в map, print может обрабатывать списки.

1 голос
/ 23 октября 2011

Причина, по которой ваш первый код не работает, заключается в том, что вы пытаетесь sequence бесконечное количество IO действий. Поскольку при этом используется строгий ввод-вывод, программе не разрешается продолжать работу до тех пор, пока не будут выполнены все действия, которые будут выполняться вечно.

Простым решением является take количество необходимых действий до их последовательности, например:

 randomW = do values <- sequence (take 10 $ repeat (randomIO :: IO Float))
              print values

Это можно написать более кратко, используя replicateM из Control.Monad:

 randomW = do values <- replicateM 10 (randomIO :: IO Float)
              print values

Или вы можете использовать randoms, чтобы составить бесконечный список случайных чисел, основанный на одном случайном семени (аналогично ответу Птивала):

 randomW = do gen <- newStdGen
              let randomValues = randoms gen :: [Float]
              print (take 10 randomValues)

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

...