Haskell错误:无法推断(随机a0)

时间:2017-02-21 09:50:55

标签: haskell

我正在玩随机函数,该函数提供了无限的随机值列表,如“了解大好的Haskell”第9章所示。代码如下:

randoms' :: (RandomGen g, Random a) => g -> [a]
randoms' gen = let (value, newGen) = random gen
               in value : randoms' newGen

为了记录随机生成器,我将randoms'改为:

randoms'' :: (RandomGen g, Random a) => g -> [(a, g)]
randoms'' gen = let (value, newGen) = random gen
                in (value, newGen) : randoms'' newGen

它按预期工作。

然后我以列表理解的方式重写了它:

randoms''' :: (RandomGen g, Random a) => g -> [(a, g)]
randoms''' gen = random gen : [random gen' | (_, gen') <- randoms''' gen]

这一次,编译器给出错误:无法推断(随机a0)因使用'randoms'''...... ......类型变量'a0'含糊不清......

但是,如果我使用具体类型指定randoms'''的类型,例如

randoms''' :: StdGen -> [(Int, StdGen)]
randoms''' gen = random gen : [random gen' | (_, gen') <- randoms''' gen]

它再次正常工作,并提供与randoms''完全相同的结果。

我想知道为什么类型推断适用于randoms''但是randoms'''失败。任何人都可以告诉我为什么这两个不等同,以及如何修复randoms'''的代码?

此外,我尝试了具有类似结构的测试代码:

generate :: (Integral a, RealFrac b) => a -> (b,a)
generate m = let x = 1.2^^m in (x, ceiling x)

foo :: (Integral g, RealFrac a) => g -> [(a,g)]
foo gen = let (value, newGen) = generate gen
          in (value, newGen) : foo newGen

foo' :: (Integral g, RealFrac a) => g -> [(a, g)]
foo' gen = generate gen : [generate gen' | (_, gen') <- foo' gen]

foo'' :: (Integral g, RealFrac a) => g -> [(a, g)]
foo'' gen = [generate gen' | gen' <- gen : map snd (foo'' gen)]

事实证明foofoo'foo''一切正常。显然,它不是单态与多态的问题。这似乎是random特有的问题。

1 个答案:

答案 0 :(得分:2)

(_, gen') <- randoms''' gen

哪种类型有_?您可能认为它应该是a签名中给出的randoms'''。但是,这是任意的。它可能是(),可能是Char。一切都可以在这里工作,因为你还是不用它。我们可以强制它与random gen'具有相同的类型:

randoms''' gen = random gen : [random gen' `asTypeOf` x | x@(_, gen') <- randoms''' gen]

asTypeOf是标准函数,基本上是const的类型约束版本:

asTypeOf :: a -> a -> a
asTypeOf = const

使用此功能,我们可以确定x的类型,从而确定_的类型,因为random gen'的类型已知。