我已经得到了这段代码,我应该解释它的非终止性并提出可能的修复方案。
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 类型上使用重复。
I have been given this snippet of code and am supposed to explain it's non termination and propose a possible fix.
randomW = do randomvalues <- sequence (repeat (randomIO :: IO Float))
print (take 10 randomvalues)
Condition for the fix is to keep generating an infinite list so we may use the take function.
I think the problem stems from the not-so-lazy nature of the sequence function, which tries to reach the end of the list generated by repeat (randomIO :: IO Float)
, leading to non termination.
I'm also not sure about whether the repeat function is possible on randomIO.
test = do random <- repeat (randomIO :: IO Float)
print random
Which yields a type error. Print can't seem to be able to handle an IO Float, which seems to suggest that you can use repeat on type IO Float.
发布评论
评论(2)
所以:
=>
因此,当您这样做时:
您实际上是在利用此处的列表 monad,因此
random
的类型为IO Float
。由于您位于列表 monad 中,因此最后一条语句需要具有类型[a]
,但它具有类型IO ()
,因为它是对print 的调用
,因此出现类型错误。序列的全部要点是将这个
[IO a]
转换为IO [a]
,您可以执行该操作来获取随机值列表,并希望打印该列表。现在,当您执行这样的 IO 时,需要一次性执行所有操作,除非使用 unsafeInterleaveIO,在这种情况下不建议这样做。所以它尝试获取无限列表...并挂起(它可能在某个时候堆栈溢出,我不确定)。要获得无限的随机值列表,您不需要所有这些,只需获取随机种子,并纯粹从种子计算随机值即可。
您应该能够使用这些 函数:
请注意,最后两个函数是纯函数。阅读此帖子可能会给您更多想法。
编辑:
如何使用
mkStdGen
的示例:我现在无法测试它,但这应该可行。不过,您可能希望使其适应您的用例。
对于您的其他问题:
=>
地图打印:: 显示 => [一]-> [IO()]
这可能不是你想要的,对吧?
如果你只是想打印一个列表,不需要
map
,print
可以处理列表。So:
=>
So when you do:
You're actually exploiting the list monad here, so
random
has typeIO Float
. Since you're in the list monad, your last statement needs to have type[a]
, but it has typeIO ()
since it's a call toprint
, hence the type error.The whole point of sequence is to transform this
[IO a]
into anIO [a]
that you can perform to obtain a list of random values, and hopefully print this list. Now, when you perform an IO like this, it needs to be performed all at once, unless usingunsafeInterleaveIO
, which is not recommended in this case. So it tries to get that infinite list... and hangs (it might stack overflow at some point, I'm not sure).To get an infinite list of random values, you don't need all this, just to obtain a random seed, and compute random values purely from the seed.
You should be able to construct an infinite list of random values using these functions:
Notice that the last two functions are pure. Reading this thread might give you some more ideas.
EDIT:
Example of how you should use
mkStdGen
:I can't test it right now but this should work. You probably want to adapt this to your use case though.
For your other question:
=>
map print :: Show a => [a] -> [IO ()]
This probably isn't what you want, right?
If you just want to print a list, no need for
map
,print
can handle lists.您的第一个代码不起作用的原因是您试图对无限数量的
IO
操作进行排序
。由于这使用了严格的 IO,因此在执行所有操作之前不允许程序继续,这将永远持续下去。一个简单的解决方案是在对它们进行排序之前
采取
您需要的操作数量,例如:可以使用
replicateM
从< code>Control.Monad:或者,您可以使用
randoms
基于单个随机种子创建无限的随机数列表(类似于Ptival的答案):在这里,我们只使用单个 IO 操作并且无限列表是基于此延迟生成的,因此没有无限数量的副作用可以运行。
The reason why your first code does not work, is that you're trying to
sequence
an infinite number ofIO
actions. Since this uses strict IO, the program is not allowed to continue before all the actions have been performed, which will take forever.A simple solution is to
take
the number of actions you need before sequencing them, for example:This can be written more succinctly using
replicateM
fromControl.Monad
:Or, you can use
randoms
to make an infinite list of random numbers based on a single random seed (similar to Ptival's answer):Here, we only use a single IO action and the infinite list is generated lazily based on that, so there is no infinite number of side effects to run.