我看到Haskell允许比较不同的数字类型:
*Main> :t 3
3 :: Num t => t
*Main> :t 3.0
3.0 :: Fractional t => t
*Main> 3 == 3.0
True
数字类型的Eq
实例的源代码在哪里?如果我创建一个新类型,例如ComplexNumber,我可以扩展==
来为它工作吗? (我可能希望没有虚部的复数可能等于实数。)
答案 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
不是a
或b
的最常用类型。事实上,所有数字文字都是多态的,但在进行任何操作(如相等比较)之前,需要将这种多态类型固定为具体的单态类型。像,
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
。
我不确定任何类型技巧可以使用用户定义的复数类型进行统一。我的直觉告诉我无法做到。