haskell fromInteger with multiple data constructors

时间:2015-10-31 14:35:54

标签: haskell constructor return

我正在寻找一种非常通用的解决方案。我的目标是找到一种干净的方式来对点(坐标)进行操作,无论是2D还是3D。我的数据Point是Num的一个实例,它提供了执行基础数学运算的函数。

data Point = Point2D Float Float
       | Point3D Float Float Float deriving Show

add :: Point -> Point -> Point
add (Point2D xa ya) (Point2D xb yb) = Point2D (xa+xb) (ya+yb)
add (Point3D xa ya za) (Point3D xb yb zb) = Point3D (xa+xb) (ya+yb) (za+zb)

divT (Point2D x y) v = Point2D (x / v) (y / v)
divT (Point3D x y z) v = Point3D (x / v) (y / v) (z / v)

fromIntegerP :: Integer -> Point
fromIntegerP v = Point2D (fromIntegral v) 0
--fromIntegerP v = Point3D (fromIntegral v) 0 0

instance Num Point where
    (+) = add
    fromInteger = fromIntegerP

p2D1 = Point2D 1.0 2.0
p2D2 = Point2D 4.0 5.0
p3D1 = Point3D 1.0 2.0 3.0
p3D2 = Point3D 6.0 6.0 6.0

main = do
    putStrLn . show $ sum [p2D1,p2D2]
    putStrLn . show $ sum [p3D1,p3D2]

此代码输出:

Point2D 5.0 7.0
*** Exception: pointStackoverflow.hs:(5,1)-(6,75): Non-exhaustive patterns in function add

...因为每个Point.fromInteger都会产生一个Point2D,即使我们期望一个Point3D。我想在“实例Num Point”中说一个方法,如果需要Point2D那么fromInteger是fromIntegerToPoint2D else fromIntegerToPoint3D。但我不知道如何根据返回类型做出选择。

任何提示?谢谢

2 个答案:

答案 0 :(得分:2)

您希望Point2DPoint3D为不同的类型,而不是相同类型的不同构造函数。

从此开始并填写定义:

data Point2D = Point2D Float Float
data Point3D = Point3D Float Float Float

instance Num Point2D where
    fromInteger = ...
    (+) = ...

instance Num Point3D where
    fromInteger = ...
    (+) = ...

答案 1 :(得分:0)

这是一个解决方案:

class Point a where
    add :: a -> a -> a
    fromIntegerP :: Integer -> a

data Point2D = Point2D Float Float deriving Show
data Point3D = Point3D Float Float Float deriving Show

instance Point Point2D where
    add (Point2D xa ya) (Point2D xb yb) = Point2D (xa+xb) (ya+yb)
    fromIntegerP v = Point2D (fromIntegral v) 0

instance Point Point3D where    
    add (Point3D xa ya za) (Point3D xb yb zb) = Point3D (xa+xb) (ya+yb) (za+zb)
    fromIntegerP v = Point3D (fromIntegral v) 0 0

instance Num Point2D where
    (+) = add
    fromInteger = fromIntegerP

instance Num Point3D where
    (+) = add
    fromInteger = fromIntegerP

p2D1 = Point2D 1.0 2.0
p2D2 = Point2D 4.0 5.0

p3D1 = Point3D 1.0 2.0 3.0
p3D2 = Point3D 6.0 6.0 6.0

main = do
    putStrLn . show $ sum [p2D1,p2D2]
    putStrLn . show $ sum [p3D1,p3D2]

我仍在寻找改进措施(instance Num Point2D whereinstance Num Point3D where),但它确实有效!

相关问题