我已经获得了这段代码,我应该解释它的非终止并提出可能的解决方案。
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。
答案 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动作,并且基于该动作懒惰地生成无限列表,因此不会有无限数量的副作用。