当*打开*单态限制时,如何解决歧义问题?
How to work around issue with ambiguity when monomorphic restriction turned *on*?
所以,学习 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
关于这个有很多 material,例如here,解决方法并不难。
我可以为 f 添加显式类型签名,也可以关闭单态限制(直接在 ghci 或 .ghci 文件中使用“:set -XNoMonomorphismRestriction”)。
有一些关于单态限制的讨论,但似乎一般的建议是关闭它是可以的(我被告知在较新版本的 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
这实际上是从 'Real World Haskell' 书中的示例代码简化而来的,它对我不起作用,您可以在此页面上找到它:http://book.realworldhaskell.org/read/monads.html(这是 Monads 章节,并且getRandom 示例函数,在该页面上搜索 'getRandom')。
如果我将单态限制 保留在 上(或将其打开),则代码可以正常工作。如果我将其更改为:
,它也可以工作(具有单态限制)
Prelude> let (a,_) = System.Random.random (System.Random.mkStdGen 4) in a :: Int
-106546976
或者如果我之前指定了 'a' 的类型:
Prelude> let (a::Int,g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int
-106546976
但是,对于第二种解决方法,我必须打开 'scoped type variables' 扩展(使用“:set -XScopedTypeVariables”)。
问题是在这种情况下(单态限制对的问题)这两种解决方法似乎都不普遍适用。
例如,也许我想编写一个函数来执行类似这样的操作并处理任意(或多种)类型,当然在这种情况下我很可能 do想要保持新的生成器状态('g')。
接下来的问题是:一般情况下,我该如何解决此类问题,而不直接指定确切的类型?
而且,如果(作为 Haskell 新手)能够更多地了解这里到底发生了什么,以及为什么会出现这些问题,那也很好..
当你定义
(a,g) = random (mkStdGen 4)
那么即使 g
本身总是类型 StdGen
,g
的 value 取决于 type of a
,因为不同的类型使用随机数生成器的程度可能不同。
而且,当你以后(假设)使用 g
时,只要a
本来就是多态的,就没办法决定您要使用哪种类型的a
来计算g
。
所以,单独来看,作为一个多态定义,上面的定义是不允许的,因为 g
实际上 是 非常模棱两可的,而这种模棱两可 不能固定在使用地点。
这是 let/where
将多个变量绑定到一个模式中的绑定的常见问题,这可能是普通单态限制比单变量方程更严格地对待它们的原因:对于一个模式,您甚至不能通过提供多态类型签名来禁用 MR。
当你改用_
时,想必GHC并不担心这种歧义,只要它不影响a
的计算。可能它可以检测到 g
在以前的版本中未被使用,并以类似的方式处理它,但显然它没有。
至于不给出不必要的显式类型的变通方法,您可以尝试将 let/where
替换为 Haskell 中的一种绑定方法,这些方法 always 单态.以下所有工作:
case random (mkStdGen 4) of
(a,g) -> a :: Int
(\(a,g) -> a :: Int) (random (mkStdGen 4))
do (a,g) <- return $ random (mkStdGen 4)
return (a :: Int) -- The result here gets wrapped in the Monad
所以,学习 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
关于这个有很多 material,例如here,解决方法并不难。 我可以为 f 添加显式类型签名,也可以关闭单态限制(直接在 ghci 或 .ghci 文件中使用“:set -XNoMonomorphismRestriction”)。
有一些关于单态限制的讨论,但似乎一般的建议是关闭它是可以的(我被告知在较新版本的 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
这实际上是从 'Real World Haskell' 书中的示例代码简化而来的,它对我不起作用,您可以在此页面上找到它:http://book.realworldhaskell.org/read/monads.html(这是 Monads 章节,并且getRandom 示例函数,在该页面上搜索 'getRandom')。
如果我将单态限制 保留在 上(或将其打开),则代码可以正常工作。如果我将其更改为:
,它也可以工作(具有单态限制)Prelude> let (a,_) = System.Random.random (System.Random.mkStdGen 4) in a :: Int
-106546976
或者如果我之前指定了 'a' 的类型:
Prelude> let (a::Int,g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int
-106546976
但是,对于第二种解决方法,我必须打开 'scoped type variables' 扩展(使用“:set -XScopedTypeVariables”)。
问题是在这种情况下(单态限制对的问题)这两种解决方法似乎都不普遍适用。
例如,也许我想编写一个函数来执行类似这样的操作并处理任意(或多种)类型,当然在这种情况下我很可能 do想要保持新的生成器状态('g')。
接下来的问题是:一般情况下,我该如何解决此类问题,而不直接指定确切的类型?
而且,如果(作为 Haskell 新手)能够更多地了解这里到底发生了什么,以及为什么会出现这些问题,那也很好..
当你定义
(a,g) = random (mkStdGen 4)
那么即使 g
本身总是类型 StdGen
,g
的 value 取决于 type of a
,因为不同的类型使用随机数生成器的程度可能不同。
而且,当你以后(假设)使用 g
时,只要a
本来就是多态的,就没办法决定您要使用哪种类型的a
来计算g
。
所以,单独来看,作为一个多态定义,上面的定义是不允许的,因为 g
实际上 是 非常模棱两可的,而这种模棱两可 不能固定在使用地点。
这是 let/where
将多个变量绑定到一个模式中的绑定的常见问题,这可能是普通单态限制比单变量方程更严格地对待它们的原因:对于一个模式,您甚至不能通过提供多态类型签名来禁用 MR。
当你改用_
时,想必GHC并不担心这种歧义,只要它不影响a
的计算。可能它可以检测到 g
在以前的版本中未被使用,并以类似的方式处理它,但显然它没有。
至于不给出不必要的显式类型的变通方法,您可以尝试将 let/where
替换为 Haskell 中的一种绑定方法,这些方法 always 单态.以下所有工作:
case random (mkStdGen 4) of
(a,g) -> a :: Int
(\(a,g) -> a :: Int) (random (mkStdGen 4))
do (a,g) <- return $ random (mkStdGen 4)
return (a :: Int) -- The result here gets wrapped in the Monad