1

我现在正在尝试使用 IORef 在 Haskell 中创建一个简单的随机数生成器来存储可变变量。这个想法是我可以初始化种子,然后根据种子生成数字,并将新种子存储为下一个随机整数。

我得到的完整错误是:

random2.hs:9:17:
    Couldn't match type `IO Int' with `Int'
    Expected type: IO (IORef Integer)
                   -> (IORef Integer -> IO Int) -> Int
      Actual type: IO (IORef Integer)
                   -> (IORef Integer -> IO Int) -> IO Int
    In a stmt of a 'do' block: seed <- newIORef 7
    In the expression:
      do { seed <- newIORef 7;
           randomGen (readIORef seed) }
    In an equation for `getRandom':
        getRandom
          = do { seed <- newIORef 7;
                 randomGen (readIORef seed) }

random2.hs:10:17:
    Couldn't match type `(,) Int' with `IO'
    Expected type: IO Int
      Actual type: (Int, Int)
    In the return type of a call of `randomGen'
    In a stmt of a 'do' block: randomGen (readIORef seed)
    In the expression:
      do { seed <- newIORef 7;
           randomGen (readIORef seed) }

random2.hs:10:28:
    Couldn't match expected type `Int' with actual type `IO Integer'
    In the return type of a call of `readIORef'
    In the first argument of `randomGen', namely `(readIORef seed)'
    In a stmt of a 'do' block: randomGen (readIORef seed)
Failed, modules loaded: none.

我不明白它为什么不能匹配类型 - 我明确表示 randomGen 需要/返回一个 Int。这是我的代码:

module Main where
    import Data.IORef

    randomGen :: Int -> (Int, Int)
    randomGen x = (x,x+1)

    getRandom :: Int
    getRandom = do
        seed <- newIORef 7
        randomGen (readIORef seed)

知道这里发生了什么吗?

谢谢,

更新代码:

module Main where
    import Data.IORef
    import Control.Monad

    randomGen :: Int -> (Int, Int)
    randomGen x = (x,x+1)

    getRandom :: IO Int
    getRandom = do
        seed <- newIORef 7
        liftM (fst (randomGen (readIORef seed)))
4

2 回答 2

3

Haskell 中的类型IO Int和类型Int完全不同。这适用于该表格的任何其他类型,例如Maybe IntEither String Int。这是 Haskell 类型系统设计的一部分,使它如此强大。您可以将这种形式的任何东西视为一种容器,它在该类型上进行了参数化。因此你可以做类似的事情

getRandom :: IO Int
getRandom = do
    seed <- newIORef 7           -- IO (IORef Int)
    g <- readIORef seed          -- IO Int
    let (x, newG) = randomGen g  -- (Int, Int)
    writeIORef seed newG         -- IO ()
    return x                     -- IO Int

但是,这将始终返回相同的值,因为种子在每次调用后都会被丢弃。我很好奇你为什么要采用这种方法来生成随机数,因为 MonadRandom 包中有这么好的 API。有关如何使用monad的示例,请参阅我不久前写的这个答案,而这个答案更深入地解释了它的工作原理。Rand

于 2014-05-12T20:19:46.677 回答
1

尝试:

module Main where
import Data.IORef
import Control.Monad
import Data.Tuple(fst,snd)

randomGen :: Int -> (Int, Int)
randomGen x = (x,x+1)

getRandom :: IO Int -> IO (Int,Int)
getRandom x = do
    y <- x
    seed <- newIORef y
    liftM randomGen $ readIORef seed

此时,使用liftM fstgetRandom 的输出来获取随机数并liftM snd获取下一次调用的种子......哦,顺便说一句System.Random,必须randoms生成一个无限的随机数列表(或任何其他Random实例)。重新发明轮子没有意义。

于 2014-05-12T20:07:02.383 回答