【问题标题】:A simple object-oriented-class 'Point' in HaskellHaskell 中一个简单的面向对象类“Point”
【发布时间】:2013-12-01 22:30:54
【问题描述】:

嗯,我确实意识到我对 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 重写

【问题讨论】:

  • 添加点的想法在数学上是奇特的。

标签: oop haskell


【解决方案1】:

首先:确实,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。这更笼统,但原则上具有相同的目的。

【讨论】:

  • 谢谢。关于 PointFamily,是的,我认为 PointFamily 中可能还有其他类型,例如 Point3D。
【解决方案2】:

为了说明 leftroundabout 关于不需要考虑 OO 的观点,我冒昧地删除了类型类,以显示代码可以多么简单。如果您目前需要编写未修改针对 2D 和 3D 点运行的代码,请不要投赞成票。但我怀疑你现在真正需要的是一个 2D 点,而这段代码可以很好地做到这一点。这是基于“你不需要它”的原则。如果后来发现你确实需要它,有几种方法可以引入它。

我还在 x 和 y 字段上添加了 bang 模式,因为典型的 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

【讨论】:

  • 只是好奇 !Float 是什么意思。
  • @cibercitizen1:它使数据字段严格,本质上是一种优化。 (通常,Haskell 值都以惰性 thunk 开始,并且只能在以后评估为具体值。在评估整个 Point 时,放入 ! 会强制执行此操作。)-顺便说一句,@ 987654321@,有时除外在未装箱的数组.
  • @GarethR 你确定类型签名中的那些p 不是太笼统吗?
  • @Ingo,感谢您的提醒。我已将它们替换为 Point2D
猜你喜欢
  • 2014-01-03
  • 2012-04-02
  • 2013-12-24
  • 2013-12-09
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 2019-02-15
  • 1970-01-01
相关资源
最近更新 更多