【发布时间】:2015-11-11 01:35:52
【问题描述】:
我正在寻找一种我认为非常通用的解决方案。我的目标是找到一种干净的方法来对点(坐标)进行操作,无论是 2D 还是 3D。我的数据点是 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。我想在“instance Num Point”中说,如果需要 Point2D,则 fromInteger 是 fromIntegerToPoint2D,否则 fromIntegerToPoint3D。但是我不知道如何根据返回类型做出选择。
有什么提示吗?谢谢
【问题讨论】:
-
看来你需要在类型级别区分
Point2D和Point3D,这样你就可以给他们不同的Num实例。 -
提示?不,事实?是的。如果您希望 fromInteger 自动将文字转换为两种形式之一,则需要为这两个点使用不同的类型。另一种类型比这有更多的好处——你对二维和三维的
Point的滥用真的很骇人听闻,这意味着像+这样的操作是部分的。例如,Point2D x y + Point3D a b c将因模式匹配不完整而失败。 -
@user2407038 和 M. DuBuisson:感谢您的回答,这是有道理的!我会尽快发布工作版本。
-
您能否从您的问题中删除解决方案并将其作为正确答案提交? (与元问题略有相关meta.stackoverflow.com/q/309266/2564301)
-
是的,感谢您的“元反馈”。
标签: haskell constructor return