使用类型类实例时自动识别类型?

时间:2017-01-21 14:38:32

标签: haskell typeclass

我正在讨论一些基本的类型类实现:

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隐含地认识到RedGreenColours但要求我专门将100绑定到Int

1 个答案:

答案 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) 100True)或isEqual (100 :: Integer) 100(这是假的)。

在实践中,这很少是一个问题,因为你不会比较不同的数字文字(这些是已知的,所以你也可以简单地硬编码结果!)但是程序中最多只有一个带有一个变量的文字,而且该变量通常已经根据上下文确定了一个类型。例如,

*Main> let b = length "foobar"
*Main> isEqual 4 b
False

没有任何签名。