我正在讨论一些基本的类型类实现:
data Colour = Red | Green | Black
class BasicEquality a where
isEqual :: a -> a -> Bool
instance BasicEquality Bool where
isEqual True True = True
isEqual False True = True
isEqual True False = True
isEqual _ _ = False
instance BasicEquality Colour where
isEqual Red Green = True
isEqual _ _ = False
instance BasicEquality Int where
isEqual 100 100 = True
isEqual _ _ = False
main = do
print $ isEqual Red Green //Output: True
print $ isEqual 100 100 //Output: Error Ambiguous type variable ‘a0’ arising from a use of ‘isEqual’
显然,当我指定print $ isEqual (100 :: Int) (100 :: Int)
为什么Haskell隐含地认识到Red
和Green
是Colours
但要求我专门将100
绑定到Int
?
答案 0 :(得分:3)
Red
等是单态值,即它们具有具体类型
Red :: Colour
因此,当代码中出现Red
时,编译器会立即知道它是什么类型,并且它可以使用此信息来推断要用于例如的类型类实例。 BasicEquality
。
OTOH,像100
这样的数字文字具有多态类型Num a => a
。原因是我们希望能够写
Prelude> replicate 3 'q'
"qqq"
以及
Prelude> sqrt 3
1.7320508075688772
如果3
只有Int
类型,则后者无效,因为sqrt
需要一种类型,例如Double
。由于数值文字实际上是多态的,所以这并不重要。
您的案例中的问题是isEqual
也是多态。因此编译器可以选择多种不同的类型。你也有的图像
instance BasicEquality Integer where
isEqual 50 1000 = True
isEqual _ _ = False
然后isEqual 100 100
可以被解释为isEqual (100 :: Int) 100
(True
)或isEqual (100 :: Integer) 100
(这是假的)。
在实践中,这很少是一个问题,因为你不会比较不同的数字文字(这些是已知的,所以你也可以简单地硬编码结果!)但是程序中最多只有一个带有一个变量的文字,而且该变量通常已经根据上下文确定了一个类型。例如,
*Main> let b = length "foobar"
*Main> isEqual 4 b
False
没有任何签名。