【发布时间】:2014-02-17 22:09:41
【问题描述】:
我想使用unsafePerformIO 将IO Int 从System.Random.MWC 转换为Int。它确实在 ghci 中工作:
Prelude System.Random.MWC System.IO.Unsafe> let p = unsafePerformIO(uniformR (0, 30) gen :: IO Int)
Prelude System.Random.MWC System.IO.Unsafe> p
11
Prelude System.Random.MWC System.IO.Unsafe> :t p
p :: Int
但是在 GHC 中
import System.Random.MWC
import System.IO.Unsafe
main :: IO()
main = do
gen <-createSystemRandom
print $! s 30 gen
s :: Int-> GenIO -> Int
s !k g = unsafePerformIO(uniformR (0, k - 1) g)
返回
ghc: panic! (the 'impossible' happened)
(GHC version 7.6.3 for i386-unknown-linux):
make_exp (App _ (Coercion _))
Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
【问题讨论】:
-
为什么会认为这样做是个好主意?这产生
IO Int而不是Int是有充分理由的:它不是 一个实际的整数值,只是获得这样一个值的“配方”。如果 ghci 实际上仅将其实现为Int类型的“隐藏”值,并且您因此能够使用unsafeCoerce获得随机数,那么这比其他任何事情都更幸运。 -
通常的回答是“它被称为 unsafe 是有原因的”,但人们经常发现明智地使用它并没有太大的缺点。然而,这不是那个时代之一——
mwc-random是一个非常积极优化的库,它在调用时解包和内联整个加载的函数体。最终结果是它为unsafe*调用提供了一个恶劣的环境。 -
啊抱歉,我看错了,您实际上并没有使用
unsafeCoerce,而只是使用了unsafePerformIO——这不太错。如果您需要将此作为随机(但请确定)算法的一部分,那么在unsafePerformIO的帮助下将其设为纯函数确实应该没问题,但只能围绕整个算法进行,因为对于单个随机数(显然不是确定性的!)这是没有意义的。然而,正如 J. Abrahamson 所说,最终结果是合理的,也不应该导致任何可能由于内联问题而发生的问题。