Haskell中为何fromDouble不是Num方法?如何让Double与Pair相加通过检查?
问题背景与疑问
我定义了如下Pair类型:
data Pair num = Pair num num
并为Pair实现了Num类型类的实例:
instance (Num num) => Num (Pair num) where (Pair x1 y1) + (Pair x2 y2) = Pair (x1 + x2) (y1 + y2) fromInteger i = Pair i i -- 其他Num方法省略
此时整数和Pair相加可以正常运行,比如:
10 + (Pair 1.0 42)
但用Double类型的数值和Pair相加时,类型检查器报错:
10.0 + (Pair 1.0 42)
报错信息如下:
No instance for (Fractional (Pair Double)) arising from the literal ‘10.0’
我知道+要求两个操作数类型相同,当期望类型是a但传入整数时,会自动调用fromInteger进行转换。那为什么Double不能被同等处理?怎么才能让10.0 + (Pair 1.0 42)通过类型检查?
问题原因与解决方法
为什么Double不能自动转换?
整数字面量(比如10)归属于Num类型类,Haskell会通过Num里的fromInteger方法把它转换成目标类型(这里就是Pair Double),而你的Pair已经实现了Num实例,所以这个转换能顺利完成。
但浮点数字面量(比如10.0)属于Fractional类型类的范畴,Haskell需要调用Fractional中的fromRational方法来完成类型转换。你的Pair只实现了Num实例,没有实现Fractional实例,类型检查器找不到对应的转换逻辑,自然就报错了。
解决方法:为Pair实现Fractional实例
要让浮点数字面量能和Pair相加,你需要为Pair实现Fractional类型类的实例,核心是实现fromRational方法,同时还要实现recip和(/)这两个必需的方法。
示例代码如下:
instance (Fractional num) => Fractional (Pair num) where fromRational r = Pair (fromRational r) (fromRational r) (Pair x1 y1) / (Pair x2 y2) = Pair (x1 / x2) (y1 / y2) recip (Pair x y) = Pair (recip x) (recip y)
实现这个实例后,10.0 + (Pair 1.0 42)就能正常通过类型检查并运行了——Haskell会自动调用fromRational把10.0转换成Pair Double类型,然后执行Num实例里定义的加法操作。
内容的提问来源于stack exchange,提问作者mvcccccc
相关产品推荐
相关产品推荐

