从randomIO列表中打印x randomIO值

时间:2011-10-20 14:38:00

标签: haskell random io functional-programming

我已经获得了这段代码,我应该解释它的非终止并提出可能的解决方案。

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

产生类型错误。打印似乎无法处理IO Float,这似乎表明您可以在IO Float类型上使用repeat。

2 个答案:

答案 0 :(得分:2)

所以:

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

=&GT;

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

所以当你这样做时:

random <- repeat (randomIO :: IO Float)

您实际上是在利用列表monad,因此random的类型为IO Float。由于您位于列表monad中,因此您的上一个语句需要具有[a]类型,但它的类型为IO (),因为它是对print的调用,因此类型错误。

序列的整个要点是将此[IO a]转换为IO [a],您可以执行该unsafeInterleaveIO以获取随机值列表,并希望打印此列表。现在,当你执行这样的IO时,它需要一次性执行,除非使用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 ,在这种情况下不推荐使用mkStdGen。所以它试图获得无限列表......并挂起(它可能在某些时候堆栈溢出,我不确定)。

要获得无限的随机值列表,您不需要所有这些,只需获取随机种子,并纯粹从种子中计算随机值。

您应该能够使用这些functions构建无限的随机值列表:

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

请注意,最后两个函数是纯函数。阅读this thread可能会给你一些更多的想法。


编辑:

您应该如何使用map :: (a -> b) -> [a] -> [b] print :: Show a => a -> IO ()

的示例
map

我现在无法测试,但这应该有效。您可能希望将其调整为您的用例。

对于您的其他问题:

print

=&GT;     map print ::显示a =&gt; [a] - &gt; [IO()]

这可能不是你想要的,对吧? 如果您只想打印列表,则无需{{1}},{{1}}可以处理列表。

答案 1 :(得分:1)

您的第一个代码不起作用的原因是,您尝试sequence无限次IO次操作。由于这使用了严格的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基于单个随机种子制作无限的随机数列表(类似于Ptival的答案):

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

在这里,我们只使用一个IO动作,并且基于该动作懒惰地生成无限列表,因此不会有无限数量的副作用。