当单形限制转向*时,如何解决模糊性问题?

时间:2015-03-22 07:46:17

标签: haskell monomorphism-restriction

所以,在学习Haskell之后,我很快就遇到了可怕的单形限制,其中包括以下内容(在ghci中):

Prelude> let f = print.show
Prelude> f 5

<interactive>:3:3:
    No instance for (Num ()) arising from the literal `5'
    Possible fix: add an instance declaration for (Num ())
    In the first argument of `f', namely `5'
    In the expression: f 5
    In an equation for `it': it = f 5

所以有很多关于此的材料,例如: here,并没有那么难以解决。 我可以为f添加显式类型签名,或者我可以关闭单态限制(使用&#34;:set -XNoMonomorphismRestriction&#34;直接在ghci或.ghci文件中)。

有一些关于单形限制的讨论,但似乎一般的建议是可以关闭它(我被告知在新版本的ghci中,这实际上是默认关闭)。

所以我把它关了。

但后来我遇到了另一个问题:

Prelude> :set -XNoMonomorphismRestriction
Prelude> let (a,g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int 

<interactive>:4:5:
    No instance for (System.Random.Random t0)
      arising from the ambiguity check for `g'
    The type variable `t0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance System.Random.Random Bool -- Defined in `System.Random'
      instance System.Random.Random Foreign.C.Types.CChar
        -- Defined in `System.Random'
      instance System.Random.Random Foreign.C.Types.CDouble
        -- Defined in `System.Random'
      ...plus 33 others
    When checking that `g' has the inferred type `System.Random.StdGen'
    Probable cause: the inferred type is ambiguous
    In the expression:
      let (a, g) = System.Random.random (System.Random.mkStdGen 4)
      in a :: Int
    In an equation for `it':
        it
          = let (a, g) = System.Random.random (System.Random.mkStdGen 4)
            in a :: Int

这实际上是从真实世界Haskell&#39;中的示例代码中简化的。这本书不适合我,你可以在这个页面上找到它:http://book.realworldhaskell.org/read/monads.html(它是Monads章节,以及getRandom示例函数,搜索&#39; getRandom&# 39;在那页上。)

如果我将单形限制保留在上(或打开它),则代码可以正常工作。如果我将其更改为:

,它也可以(具有单态限制)
Prelude> let (a,_) = System.Random.random (System.Random.mkStdGen 4) in a :: Int 
-106546976

或者如果我指定&#39; a&#39;早期:

Prelude> let (a::Int,g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int
-106546976

但是,对于第二种解决方法,我必须打开&#39;作用域类型变量&#39;扩展名(使用&#34;:set -XScopedTypeVariables&#34;)。

问题在于,在这种情况下(单态限制 on 时的问题),这两种解决方法似乎都不适用。

例如,也许我想编写一个类似这样的函数并使用任意(或多个)类型,当然在这种情况下我很可能想要坚持新的生成器状态(&#39; g&#39;)。

问题是:一般来说,如何解决这类问题,而不直接指明确切的类型?

而且,作为一名Haskell新手,能够更好地了解这里发生了什么,以及为什么会出现这些问题,这也很棒。

1 个答案:

答案 0 :(得分:3)

定义时

(a,g) = random (mkStdGen 4)

然后,即使g本身始终属于StdGen类型,g也取决于{的类型 {1}},因为不同的类型在使用随机数生成器的程度上可能不同。

此外,当您(假设)稍后使用 a时,只要g最初是多态的,就无法决定哪个您要用于计算a的{​​{1}}类型。

因此,单独作为多态定义,上述内容必须被禁止,因为a实际上 非常模糊,并且这种歧义不能被修复使用网站。

这是绑定模式中几个变量的g绑定的一般问题,这可能是普通单态限制对待它们甚至比单变量方程更严格的原因:使用模式,你不能甚至通过给出多态类型签名来禁用MR。

当您使用g时,只要它不影响let/where的计算,大概GHC就不会担心这种歧义。可能它可能检测到_在前一版本中未使用,并且对其进行了类似处理,但显然它没有。

对于没有给出不必要的显式类型的变通方法,您可以尝试用Haskell中的一个始终单态的绑定方法替换a。以下所有工作:

g