2017-02-21 43 views
2

我在随机函数中播放随机函数,该函数给出了一个随机值的无限列表,如“了解您对Haskell的好作品”第9章所示。该代码是这样的:Haskell错误:无法推断(随机a0)产生于

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) ......类型变量 '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

您抛弃了由'randoms''''('(_,gen')< - ...')生成的实际值,因此编译器不知道在哪种类型上实例化使用'randoms'' “';没有理由选择相同类型的'a'作为输出,也没有其他特殊类型,所以它是不明确的。在单形的情况下,没有可能的实例 - 当然它可能只为递归情况选择“Int”。 – user2407038

回答

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

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

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

asTypeOf是一个标准的功能和基本的const类型受限版本:

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

有了这个功能,我们可以判断的类型x,因此_的类型,因为random gen'的类型是已知的。

+0

您使用'asTypeOf'的第一个解决方案解决了这个问题。然而,第二个解决方案'randomList'会产生几乎完全相同的错误信息(如果类型签名被设置为单形的话,它将再次起作用)。我仍然没有明白为什么'_'的类型只是因为它没有被使用而是任意的;无论如何,在单形的情况下不存在这样的问题。也许类型推断的机制在单形和多形的情况下有所不同? – Oyu

+0

@Oyu我删除了错误的功能。我不知道为什么它在我尝试过时发挥作用。无论哪种方式,'_'都是“使用”的。它是“随机”调用结果的一部分。如果我们使用'let(val,gen)= random(mkStdGen 0)::(a,StdGen)',根据类型我们会得到另一个生成器gen。对于'a〜Int',我们得到'(9106162675347844341,1346387765 2103410263)'。对于'a〜Char',我们得到'('\ 589059',40014 40692)'。毕竟,你必须经常调用'next'来创建一个统一的分布来覆盖整个数值范围。 – Zeta

+0

我已经在我的原始文章结尾重新编辑了一些foo代码。你能给我一些关于你的想法的评论吗? – Oyu