我们假设我在GHCi中执行以下代码:
[unsafePerformIO (randomRIO (0,1)) | _ <- [1..10]].
Run Code Online (Sandbox Code Playgroud)
[1,1,0,0,1,0,0,0,0,1]
每次执行此操作时,结果可能看起来都不同.现在假设我定义了以下函数:
f :: Int
f = unsafePerformIO (randomRIO (0,1))
Run Code Online (Sandbox Code Playgroud)
并试着打电话:
[f | _ <- [1..10]].
Run Code Online (Sandbox Code Playgroud)
结果总是如此[0,0,0,0,0,0,0,0,0,0]
.如果我只是打一个电话f
,它总是返回0.暂且说我不应该把IO扔掉,我做错了什么?
你做错了就是使用unsafePerformIO
,特别是当你知道它不会是一个功能时 - 它会为相同的输入提供不同的输出.
你的邪恶使用的原因unsafePerformIO
并不像你想象的那样f
,这不是一个功能,它是以常量的应用形式.它只会被评估一次,并且每次都是相同的.您可以通过将其定义更改为来查看此内容
f :: Int
f = unsafePerformIO (putStrLn "generating" >> randomRIO (0,1))
Run Code Online (Sandbox Code Playgroud)
"生成"只打印一次.
写一个邪恶的"功能",写
g :: a -> Int
g a = unsafePerformIO (randomRIO (0,1))
print [g x | x <- [1..10]]
Run Code Online (Sandbox Code Playgroud)
x
即使它们具有相同的值,也将对每个进行一次评估.你可以通过评估看出这是多么邪恶
print [g x | x <- [1,1,1,1,1,1,1]]
Run Code Online (Sandbox Code Playgroud)
"功能"对同一输入有不同的输出!把所有东西都放在Unsafe
一边,直到你确定你需要它并确定你理解它,然后无论如何都不管它.