1

如何让下面的代码用于比较不同的数字类型?

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

我从上下文 (Num a, Num b) 中推断出 (a ~ b) 时出错

4

2 回答 2

8

首先,您的类型签名在语法上是错误的(根据我对报告中的上下文无关语法的阅读,尽管 GHC 接受它),它应该是

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

关于这个问题,你不能这样做,(<)有 type Ord a => a -> a -> Bool,所以两个参数必须具有相同的类型。

有了比 just 更强的限制Num,例如,您可以拥有

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

您需要能够将两个参数转换为相同的目标类型(通过有意义的转换)来比较这些值。对于类中的Real类型,toRational提供到公共目标类型的这种转换(如果起始类型是浮点类型,则警告toRational不适用于 NaN 和无穷大)。对于约束toInteger将达到相同的效果。Integral

只有一个Num约束,没有这样的通用目标类型可用。

对于您的特殊需要,您可以选择一个目标类型并定义一个

class Convertible a where
    toTarget :: a -> Target

如果RealIntegral不是可行的约束。

于 2012-10-07T00:57:19.793 回答
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
于 2012-10-07T00:57:41.393 回答