【问题标题】:haskell Convert IO Int to Int System.Random.MWChaskell 将 IO Int 转换为 Int System.Random.MWC
【发布时间】:2014-02-17 22:09:41
【问题描述】:

我想使用unsafePerformIOIO IntSystem.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 所说,最终结果是合理的,也不应该导致任何可能由于内联问题而发生的问题。

标签: haskell io


【解决方案1】:

这里真的不需要unsafePerformIO。只需将s 的类型更改为返回IO Int 并使用do-notation 或绑定运算符将结果提供给print

s :: Int -> GenIO -> IO Int
s k g = uniformR (0, k - 1) g

main :: IO ()
main = do
    gen <- createSystemRandom
    x <- s 30 gen
    print x

main = do
    gen <- createSystemRandom
    print =<< s 30 gen

main = print =<< s 30 =<< createSystemRandom

【讨论】:

  • 我需要程序中的结果。实际上,我想将排列随机选择为转置的产物(Fisher Yates 算法)
  • @user2746080:在这种情况下,您应该修改您的代码以在IO 中也能工作,并使用 do-notation 编写您的 shuffle 函数。然后你可以使用&lt;- 得到结果,就像我在这里所做的那样。
  • 使用 System.Random 我的 Shuffle 函数: shuffle :: [Integer] -> Integer -> [Integer] shuffle xs 1 = xs shuffle !xs !k = shuffle (sswap (unsafePerformIO (getStdRandom (randomR (0 , k - 1))) ) k xs) (k - 1) 并调用 sswap 函数: sswap :: Integer -> Integer -> [Integer] -> [Integer] sswap !i !j !xs = genericTake i xs ++ [xs !! (fromIntegral j)] ++ (genericTake (j - i - 1) $ genericDrop (i + 1) xs) ++ [xs !! (fromIntegral i)] ++ genericDrop (j + 1) xs 它工作正常,但我不知道用 do 表示法编写它。感谢帮助。
  • @user2746080 也许你应该阅读一下 do-notation 和 monads:en.wikibooks.org/wiki/Haskell/do_Notation
  • 不,它不能“正常工作”。幸运的情况是让它在你的情况下做你想做的事情。
猜你喜欢
  • 2011-05-13
  • 1970-01-01
  • 2014-06-02
  • 2020-06-11
  • 1970-01-01
  • 2011-02-16
  • 2012-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多