嗨,我是haskell编程的新手,我写了这段代码:
f :: a->Bool
f x = True
g :: a->Bool
g x = False
class P a where
func :: a->Bool
instance P Integer where
func x = f x
instance P Float where
func x = g x
如果我将函数func
称为func 23.3
,Ghci将返回以下错误:
<interactive>:6:6:
Ambiguous type variable a0' in the constraints:
(Fractional a0)
arising from the literal 23.3' at <interactive>:6:6-9
(P a0) arising from a use of func' at <interactive>:6:1-4
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of func', namely 23.3'
In the expression: func 23.3
In an equation for it': it = func 23.3
虽然如果我用Integer作为参数调用func
,代码工作正常。如果我用Float
实例替换P的Double
实例,则代码可以与调用func 23.3
一起正常工作。为什么?
答案 0 :(得分:4)
这是臭名昭着的单态限制。 GHCi不知道将23.3
转换为具体的类型,并且有多种Fractional a
数据类型(特别是Double
和Float
)。
您可以使用
禁用此功能> :set -XNoMonomorphismRestriction
或者更好
> func (23.3 :: Float)
原因是因为文字23.3
的类型为
> :type 23.3
23.3 :: Fractional a => a
而不是像Float
或Int
这样更具体的类型。这实际上允许您实现自己的类型,可以用数字文字表示(有时是一个方便的技巧)。不幸的是,它给出了一个相当无益的错误信息,让每个初学者都感到困惑。但是,编译器必须具有特定类型,因为您还可以添加
instance P Double where
func x = undefined
然后它必须决定func
的哪个实例用于像23.3
这样的文字。最佳做法是仅指定您使用内联的类型,如上所示。
可能之所以它在GHCi中使用Double
的原因是因为GHCi有时会尝试将类型强制转换为更方便的东西。这就是为什么你要这样做
> let x = [1..]
> :type x
x :: [Integer]
而x
应该有(Enum a, Num a) => [a]
类型。如果启用了Monomorphism限制(默认情况下),GHCi将尝试使类型与Integer
,Double
,IO
一起使用,而不是Integral a => a
,{{ 1}}或Double a => a
。它并不适用于所有情况。