如何在不假设固定位数的情况下读取足够的数据来反序列化 Int 类型的种子?

How do I read enough data to deserialize a seed of type Int without assuming a fixed number of bits?

我们得到 mkStdGen has type IntStdGenInt 定义为

A fixed-precision integer type with at least the range [-2^29 .. 2^29-1]. The exact range for a given implementation can be determined by using minBound and maxBound from the Bounded class.

换句话说,Int的宽度没有固定的上限。

Expert Beginner 可能会想,'但是 GHC 在我的机器上使用 31 位 Int - 对 Simon Peyton Jones 来说足够好应该对任何人都足够好!'并且非常自我满足写

generator :: IO StdGen
generator = do
  withBinaryFile "/dev/urandom" ReadMode $ \h -> do
    let nbytes = 4
        buf = take nbytes $ repeat (0::Word8)
        toInt ws =
          let [a,b,c,d] = (map fromIntegral ws) :: [Word32] in
            fromIntegral $ (shiftL (clearBit a 7) 24) .|.
                           (shiftL           b    16) .|.
                           (shiftL           c     8) .|. d
    withArray buf $ \p -> do
      nread <- hGetBuf h p nbytes
      when (nread /= nbytes) $ error "failed read"
      bytes <- peekArray nbytes p
      return $ mkStdGen (toInt bytes)

我们的英雄没有想到要检查 64 位 GHC:

Prelude> maxBound :: Int
9223372036854775807
Prelude> 2^63
9223372036854775808

或其他 Haskell 其 Int 具有最小 29 位。

我们如何实现 generator 以避免浪费或溢出种子位?

FiniteBits class 得到了您的支持。

Data.Bits> finiteBitSize (0 :: Int)
64