所以,在学习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新手,能够更好地了解这里发生了什么,以及为什么会出现这些问题,这也很棒。
答案 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