1

我定义了以下数据类型:

data NewBool = Truth | Lie deriving (Show)

我创建了一个函数,它应该返回一个随机的 NewBool​​ 值

giveMeBool :: IO()
giveMeBool = do 
     bool <- randomIO :: IO NewBool
     putStrLn("Your random boolean is"++ show bool)

我在这里读到,我必须使 NewBool​​ 成为 Random 的实例才能使用 randomIO。所以我这样做了:

 instance Random NewBool where
 random g = case random g of
              (r,g')  | r < (1/2)= (Truth, g')
                      | otherwise= (Lie, g')

真诚地,这只是我在另一篇文章中找到的内容的复制和粘贴,但我不明白它是如何工作的?r 的值和类型是如何定义的?谁能帮我?谢谢 ;)

4

1 回答 1

6

既然random有类型(本质上)

random :: Random a => StdGen -> (a, StdGen)

如果你将它传递给StdGeng,它会给你一个实例化Random类型的任何类型的值。编译器通过你如何使用它来猜测你需要什么类型。在您的情况下,它在片段中使用

r < (1/2)

我们可以检查每件作品的类型

(<)   :: Ord a => a -> a -> Bool
(1/2) :: Fractional a => a

这意味着完整的类型r

r :: (Random a, Fractional a, Ord a) => a

这还不足以让 Haskell 继续进行,但由于这在数字类型中很常见(因为数字文字解析为不明确的类型,而不是具体的数字类型)Haskell 有一个“默认”系统。特别是以下default配置生效(默认)

default (Integer, Double)

这意味着如果您有一个模棱两可的类型,受类约束,并且可以满足这些类中的任一个IntegerDouble可以满足这些类,那么按照该顺序,这些具体类型将被替换。在 的情况下rDouble实例化RandomOrdFractional因此编译器选择r :: Double

最后,我们考虑恰好在区间上选择随机值的Random实例。这意味着它有 50% 的机会大于,因此每个和构造函数都将以相同的几率被选中。DoubleDouble(0,1)(1/2)TruthLie


最后,为了真正实现Random NewBool,最好将实例从与Bool.

instance Random NewBool where
  random g = case random g of
    (True,  g') -> (Truth, g')
    (False, g') -> (Lie,   g')

虽然这仅在您不想修改随机生成器的行为时才有效Random Bool。但是,请注意这里发生了类似的类型解析——除了它被大大简化了,因为我正在匹配模式True并且False这立即意味着返回类型random g 必须(Bool, StdGen).

于 2014-03-20T13:08:32.073 回答