zw3*_*324 7 haskell types ghci type-variables
我正在阅读LYAH,在第9章中,我发现了一个奇怪的问题.作者提供了实现"randoms"功能的示例:
randoms' :: (RandomGen g, Random a) => g -> [a]
randoms' gen = let (value, newGen) = random gen in value:randoms' newGen
Run Code Online (Sandbox Code Playgroud)
好吧,这个编译得很好.但是,如果我将第二行更改为:
randoms' gen = (fst (random gen)) : (randoms' (snd (random gen)))
Run Code Online (Sandbox Code Playgroud)
此文件报告加载时出错:
IOlesson.hs:4:52:
Ambiguous type variable `a' in the constraint:
`Random a' arising from a use of `random' at IOlesson.hs:4:52-61
Probable fix: add a type signature that fixes these type variable(s)
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)
如果我将此行更改为:
randoms' gen = (fst (random gen)) : (randoms' gen)
Run Code Online (Sandbox Code Playgroud)
然后这将做得很好,并且如预期的那样,这将返回所有相同元素的列表.
我很困惑:Miran的版本和我的版本有什么不同?
谢谢你的任何想法!
问题是random接受任何实例RandGen,并返回一个随机值和一个相同类型的新生成器.但随机值可以是任何类型的实例Random!
random :: (Random a, RandomGen g) => g -> (a, g)
Run Code Online (Sandbox Code Playgroud)
所以,当你random在递归中第二次调用时,它不知道第一个元素的类型应该是什么!没错,你真的不关心它(你把它扔掉用snd,毕竟),但选择一个可以影响行为的random.所以要消除歧义,你需要告诉GHC你想要的是什么.最简单的方法是重写您的定义,如下所示:
randoms' gen = let (value, gen') = random gen in value : randoms' gen'
Run Code Online (Sandbox Code Playgroud)
因为您使用value结果列表的一部分,所以它被强制与类型签名中的a具有相同的类型- 结果列表的元素类型.解决了歧义,并且避免了下一个随机数的重复计算,以进行引导.有一些方法可以更直接地消除歧义(保留重复计算),但它们要么丑陋又令人困惑或涉及语言扩展.值得庆幸的是,你不应该经常遇到这种情况,当你这样做时,这样的方法应该可以解决这种模糊性.
同样地,也许更整洁,你可以写:
randoms' gen = value : randoms' gen'
where (value, gen') = random gen
Run Code Online (Sandbox Code Playgroud)