Haskell中一个简单的面向对象的类'Point'

时间:2013-12-01 22:30:55

标签: oop haskell

嗯,我确实认识到我对haskell感到困惑,这是我第一个周末。

我只是想知道以下设计的OO-class Point2D

UML design of 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重写

2 个答案:

答案 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