等式如何适用于数字类型?

时间:2016-08-01 20:24:48

标签: haskell typeclass

我看到Haskell允许比较不同的数字类型:

*Main> :t 3
3 :: Num t => t
*Main> :t 3.0
3.0 :: Fractional t => t
*Main> 3 == 3.0
True

数字类型的Eq实例的源代码在哪里?如果我创建一个新类型,例如ComplexNumber,我可以扩展==来为它工作吗? (我可能希望没有虚部的复数可能等于实数。)

2 个答案:

答案 0 :(得分:10)

“Haskell允许比较不同的数字类型”,不,它没有。 Haskell实际允许的是由相同的文字定义的不同类型。特别是,你可以做到

Prelude> let a = 3.7 :: Double
Prelude> let b = 1   :: Double
Prelude> a + b
4.7

OTOH,如果我明确地使用冲突类型声明这些,则添加将失败:

Prelude> let a = 3.7 :: Double
Prelude> let b = 1   :: Int
Prelude> a + b

<interactive>:31:5:
    Couldn't match expected type ‘Double’ with actual type ‘Int’
    In the second argument of ‘(+)’, namely ‘b’
    In the expression: a + b

现在,Double不是ab的最常用类型。事实上,所有数字文字都是多态的,但在进行任何操作(如相等比较)之前,需要将这种多态类型固定为具体的单态类型。像,

Prelude> (3.0 :: Double) == (3 :: Double)
True

因为==与你的前提相反,实际上要求双方都有相同的类型,你可以省略任何一方的签名而不改变任何东西:

Prelude> 3.0 == (3 :: Double)
True

事实上,即使没有任何类型的注释,GHCi仍然会将双方视为Double。这是因为type defaulting - 在这种特殊情况下,Fractional是共享数字类型的最强约束,对于Fractional,默认类型为Double。 OTOH,如果双方都是完整的文字,那么GHCi会选择Integer。这有时会产生影响,例如

Prelude> 10000000000000000 == 10000000000000001
False

Prelude> 10000000000000000 ==(10000000000000001 :: Double)
True

因为在后一种情况下,最后的1在浮点错误中丢失。

答案 1 :(得分:2)

这里没有什么神奇的事情发生。 3可以是实数或整数,但与3.0相比,其类型与实数统一。

注意类型类:

class Eq a where
  eq :: a -> a -> Bool

所以eq确实只比较相同类型的东西。您的示例3 == 3.0统一了其类型,并在内部变为3.0 == 3.0

我不确定任何类型技巧可以使用用户定义的复数类型进行统一。我的直觉告诉我无法做到。