如何让下面的代码用于比较不同的数字类型?
foo::(Num a) => (Num b) => a -> b -> Bool
foo a b = (a == b)
我从上下文 (Num a, Num b) 中推断出 (a ~ b) 时出错
如何让下面的代码用于比较不同的数字类型?
foo::(Num a) => (Num b) => a -> b -> Bool
foo a b = (a == b)
我从上下文 (Num a, Num b) 中推断出 (a ~ b) 时出错
首先,您的类型签名在语法上是错误的(根据我对报告中的上下文无关语法的阅读,尽管 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
如果Real
或Integral
不是可行的约束。
这应该是不可能的——因为不是每个都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