Haskell 当单态限制打开*时,如何解决歧义问题?

Haskell 当单态限制打开*时,如何解决歧义问题?,haskell,monomorphism-restriction,Haskell,Monomorphism Restriction,因此,在学习Haskell的过程中,我很快就遇到了可怕的单态限制(在ghci中): 或者如果我在前面指定了“a”的类型: Prelude> let (a::Int,g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int -106546976 但是,对于第二种解决方法,我必须启用“作用域类型变量”扩展(使用“:set-XScopedTypeVariables”) 问题是,在这种情况下(单态限制时的问题),两种变通方法

因此,在学习Haskell的过程中,我很快就遇到了可怕的单态限制(在ghci中):

或者如果我在前面指定了“a”的类型:

Prelude> let (a::Int,g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int
-106546976
但是,对于第二种解决方法,我必须启用“作用域类型变量”扩展(使用“:set-XScopedTypeVariables”)

问题是,在这种情况下(单态限制时的问题),两种变通方法似乎都不普遍适用

例如,我可能想编写一个函数,它可以执行类似的操作,并且可以处理任意(或多个)类型,当然,在这种情况下,我很可能希望保留新的生成器状态(在“g”中)

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

(作为Haskell的新手)更好地了解这里到底发生了什么,以及为什么会出现这些问题。

当您定义

(a,g) = random (mkStdGen 4)
然后,即使
g
本身始终是类型
StdGen
g
的值取决于
a
的类型,因为不同类型在使用随机数生成器的程度上可能不同

此外,当您(假设)稍后使用
g
时,只要
a
最初是多态的,就无法确定要使用哪种类型的
a
来计算
g

因此,单独来看,作为多态性定义,上述定义必须被禁止,因为
g
实际上是非常模糊的,并且这种模糊性不能在使用现场修复

这是绑定模式中多个变量的
let/where
绑定的一般问题,可能是普通单态约束比单变量方程更严格的原因:对于模式,您甚至不能通过提供多态类型签名来禁用MR

当您改为使用
\uuu
时,只要不影响
a
的计算,GHC大概不会担心这种模糊性。它可能检测到
g
在前一版本中未使用,并对其进行了类似的处理,但显然没有

至于不提供不必要的显式类型的变通方法,您可以尝试用Haskell中的一个绑定方法替换
let/where
,该方法始终是单态的。以下是所有工作:

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
的随机案例(mkStdGen 4)
(a,g)->a::Int
(\(a,g)->a::Int)(随机(mkStdGen 4))

做(a,g)点。我有一个很难回答的问题,你认为以下是GHC错误吗:
x::Random a=>a;x=let(a,b)=a中的随机(mkStdGen 0)
类型检查有单态限制,但没有它不会检查!(在GHC 7.8.4中)。在我看来,解除限制会导致更少的程序需要检查,这真的很奇怪。@AndrásKovács在我开始写我的答案之前,我认为这是一个bug,但现在我大约是50/50:P
Prelude> let (a::Int,g) = System.Random.random (System.Random.mkStdGen 4) in a :: Int
-106546976
(a,g) = random (mkStdGen 4)
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