如何使用以下代码来比较不同的数字类型?
foo::(Num a) => (Num b) => a -> b -> Bool
foo a b = (a == b)
我从上下文(Num a,Num b)中得到关于推导(a~b)的错误
答案 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
如果Real
或Integral
不是可行的约束。
答案 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