嗯,我确实认识到我对haskell感到困惑,这是我第一个周末。
我只是想知道以下设计的OO-class Point2D
应该用Haskell编写如下:
import Prelude hiding ( sum )
-- ...............................................................
-- "class type" : types belonging to this family of types
-- must implement distance and sum functions
-- ...............................................................
class PointFamily p where
-- p is a type of this family, not a point
distance :: p -> p -> Float -- takes two things of type p and returns a Real
sum :: p -> p -> p -- takes two things of type p and returns a p thing
-- ...............................................................
-- data type: Point2D
-- a new type with x and y coordinates
-- ...............................................................
data Point2D = Point2D { x :: Float , y :: Float }
deriving (Show) -- it is "showable/printable"
-- ...............................................................
-- Point2D belongs to PointFamily, so let's say it and
-- how to compute distance and sum for this type
-- ...............................................................
instance PointFamily Point2D where
-- ............................................................-
distance p1 p2 = sqrt (dx*dx + dy*dy)
where
dx = (x p1) - (x p2)
dy = (y p1) - (y p2)
-- ............................................................-
sum p1 p2 = Point2D { x = (x p1)+(x p2), y = (y p1)+(y p2) }
-- ...............................................................
-- global constant
-- ...............................................................
origin = Point2D 0.0 0.0
-- ...............................................................
-- main
-- ...............................................................
main = do
putStrLn "Hello"
print b
print $ distance origin b
print $ sum b b
where
b = Point2D 3.0 4.0
是的,我知道我不应该尝试在Haskell中“思考OOP”,但是......好吧,1)这需要很长时间,2)在实践中我猜你会发现几个OOP设计在Haskell重写
答案 0 :(得分:10)
首先:确实,you should try not to "think OOP" in Haskell!
但是你的代码根本不是OOP。如果您开始尝试虚拟继承等,那将是OO,但在此示例中,OO实现更像是明显的Haskell实现。
只有,应该强调的是,类型类PointFamily
实际上与数据类型Point2D
没有任何特定的1:1关系,就像它们在OO类中的捆绑一样。实际上,您可以为可以想象的任何类型创建此类的实例。不出所料,以前所有这一切都已经完成; PointFamily
的最广泛等价物是AffineSpace
from the vector-spaces
package。这是更普遍的,但原则上有很多相同的目的。
答案 1 :(得分:2)
为了说明leftroundabout关于不需要考虑OO的观点,我冒昧地删除了类型类,以显示代码是多么简单。如果您目前需要能够编写未经修改对2D和3D点的代码,请不要投票。但我怀疑你现在真正需要的是一个2D点,这段代码做得很好。这是关于“你不需要它”的原则。如果事后证明你确实需要它,有几种方法可以引入它。
我还在x和y字段上添加了爆炸模式,因为典型的2D应用程序通常希望这些字段是严格的。
import Prelude hiding ( sum )
data Point2D = Point2D { x :: !Float , y :: !Float }
deriving (Read,Show,Eq)
distance :: Point2D -> Point2D -> Float -- takes two things of type p and returns a Real
distance p1 p2 = sqrt (dx*dx + dy*dy)
where
dx = (x p1) - (x p2)
dy = (y p1) - (y p2)
sum :: Point2D -> Point2D -> Point2D -- takes two things of type p and returns a p thing
sum p1 p2 = Point2D { x = (x p1)+(x p2), y = (y p1)+(y p2) }
origin = Point2D 0.0 0.0
main = do
putStrLn "Hello"
print b
print $ distance origin b
print $ sum b b
where
b = Point2D 3.0 4.0