我正在玩随机函数,该函数提供了无限的随机值列表,如“了解大好的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)]
事实证明foo
,foo'
和foo''
一切正常。显然,它不是单态与多态的问题。这似乎是random
特有的问题。
答案 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'
的类型已知。