【发布时间】:2017-02-22 00:29:30
【问题描述】:
我在玩随机函数,它给出了一个无限的随机值列表,如“Learn You a Haskell for Great Good”的第 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]
这一次,编译器给出了错误:Could not deduc (Random a0) generated from a use of '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 特有的问题。
【问题讨论】:
-
您丢弃了
randoms'''((_, gen') <- ...) 生成的实际值,因此编译器不知道使用哪种类型实例化randoms''';它没有理由选择与输出相同的类型a,也没有任何其他特定类型,因此它是模棱两可的。在单态情况下,不可能实例化 - 自然它可能只会选择Int用于递归情况。
标签: haskell