不同数字类型的不等式

时间:2012-10-07 00:32:40

标签: haskell

如何使用以下代码来比较不同的数字类型?

foo::(Num a) => (Num b) => a -> b -> Bool
foo a b = (a == b)

我从上下文(Num a,Num b)中得到关于推导(a~b)的错误

2 个答案:

答案 0 :(得分:8)

首先,你的类型签名在语法上是错误的(根据我在报告中对the context-free syntax的解读,尽管GHC接受它),它应该是

foo::(Num a, Num b) => a -> b -> Bool

关于这个问题,您不能这样做,(<)的类型为Ord a => a -> a -> Bool,因此两个参数的类型必须相同。

如果限制强于Num,则可以使用

bar :: (Real a, Real b) => a -> b -> Bool
bar a b = toRational a < toRational b

您需要能够将两个参数转换为相同的目标类型(通过有意义的转换)来比较这些值。对于Real类中的类型,toRational提供了对常见目标类型的转换(如果起始类型为a,则toRational无法合理地使用NaN和无穷大。浮点类型)。对于toInteger约束,Integral会达到相同的效果。

只有Num约束,没有这种常见的目标类型。

为满足您的特殊需求,您可以选择目标类型并定义

class Convertible a where
    toTarget :: a -> Target

如果RealIntegral不是可行的约束。

答案 1 :(得分:4)

这是不可能的 - 因为并非每个Num都具有可比性 - 比如说你甚至有

foo :: Num a => a -> b -> Bool
foo x y = x < y

然后将它用于复数,你会使用<的概念吗?词典顺序是一种选择,但不清楚它是否有意义。

如果你有两种不同的数字类型,我会问你:“你如何比较复数和实数?或者小时数,通过使用模数计算可以成为Num的实例,使用分钟? “

如果您使用Real a作为约束,那么您将拥有toRational函数 - 解决可比性问题的一种方法。

foo :: (Real a, Real b) => a -> b -> Bool
foo x y = x' < y'
        where x' = toRational x
              y' = toRational y