标题可能不合适,因此请继续阅读。

我最初想要的是以下内容:我正在编写2D矢量数据

data Vect a = Vect a a deriving (Show)


并想编写一个适用于所有norm :: Vect a -> DoubleVect a函数,其中a是IntegralFloating的实例。

对于Double,我可以这样写:

norm :: Vect Double -> Double
norm (Vect x y) = sqrt  $ x^2 + y^2


但我希望此功能也可以与Vect Int一起使用。我可以编写另一个函数,例如:

normFromInt :: (Integral a) => Vect a -> Double
normFromInt (Vect x y) = sqrt . fromIntegral $ x^2 + y^2


具有两个功能似乎很尴尬。有什么好的方法可以做到这一点?



我试图为此使用特殊类:

class Vectorlike a where
    norm :: a -> Double

instance (Integral a) => Vectorlike (Vect a) where
    norm (Vect x y) = sqrt . fromIntegral $ x^2 + y^2
-- |
-- >>> norm (Vect 3 4 :: Vect Int)
-- 5.0

instance Vectorlike (Vect Double) where
    norm (Vect x y) = sqrt $ x^2 + y^2


但是有了这个,当usnig`norm(Vect 3.0 4.0 :: Vect Double)我得到一个错误

Overlapping instances for Vectorlike (Vect Double)
||   print $ norm (Vect 3.0 4.0 :: Vect Double)
foo.hs|40 col 13 error| Overlapping instances for Vectorlike (Vect Double)
||   arising from a use of `norm'
|| Matching instances:
||   instance Integral a => Vectorlike (Vect a)
||     -- Defined at /home/yosh/foo.hs:26:10
||   instance Vectorlike (Vect Double)
||     -- Defined at /home/yosh/foo.hs:32:10


我的问题是如何定义norm使其适用于整数和浮点数,并且错误消息不是主要问题(这令人困惑,但我认为以后可以使用它)。

最佳答案

您只需要使用realToFrac,它将任何Real r => r值转换为Fractional f => f值:

norm :: (Real r, Floating f) => Vect r -> f
norm (Vect x y) = sqrt . realToFrac $ x^2 + y^2


然后,它将不仅适用于Double的更多类型。

至于错误消息,从技术上讲,这两个实例没有重叠,但是您绝对可以。有人可以定义一个Integral Double实例,然后导入您的代码。突然,编译器无法决定要使用哪个实例!

尽管这种精确的情况不太可能发生,但是类型系统确实允许某人为Integral实例化Double,并且其他类型类和数据类型当然也可能发生这种情况。

关于haskell - 类型变量具有多态性?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30180737/

10-12 12:45
查看更多