2013-12-01 2 views
7

Ну, я признаю, что я озадачен haskell и что это мои первые выходные с ним.Простой объектно-ориентированный класс «Точка» в Haskell

Мне просто интересно, если следующий дизайн ОО-класса 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, но ... ну, 1) это займет много времени, и 2) на практике я предполагаю, что вы найдете несколько проектов ООП, которые будут перезаписаны в Haskell.

+0

Идея добавления * точек является математически своеобразной. – dfeuer

ответ

10

Прежде всего: действительно, you should try not to "think OOP" in Haskell!

Но ваш код на самом деле не ООП. Это было бы OO, если бы вы начали использовать виртуальное наследование и т. Д., Но в этом примере, скорее всего, реализация OO похожа на очевидную реализацию Haskell.

Только, следует подчеркнуть, что тип класса PointFamily действительно не имеет конкретного отношения 1: 1 к типу данных Point2D, как и их связывание в классе OO. Вы бы на практике делали экземпляры этого класса для любого типа, где он, по-видимому, работает. Неудивительно, что все это было сделано раньше; наиболее распространенным эквивалентом PointFamily является AffineSpace from the vector-spaces package. Это намного более общий, но в принципе имеет ту же цель.

+0

Спасибо. О PointFamily, да, я думал, что в PointFamily могут быть и другие типы, такие как, очевидно, Point3D. – cibercitizen1

2

Просто, чтобы проиллюстрировать точку влево, о том, что вам не нужно думать о 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 
+0

Просто интересно, что! Float означает. – cibercitizen1

+1

@ cibercitizen1: он создает поля данных _strict_, по существу, оптимизацию. (Обычно значения Haskell начинаются как ленивые thunks и могут быть оценены только по конкретным значениям позже. Включение в '!' Заставляет это право, когда оценивается «Point» в целом.) - BTW, [используя 'Float' doesn [Xaskell.org/haskellwiki/Performance/Floating_point], за исключением иногда в _unboxed arrays_. – leftaroundabout

+0

@GarethR вы уверены, что эти 'p' в подписи типов не слишком общие? – Ingo

Смежные вопросы