Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A simple object-oriented-class 'Point' in Haskell

Tags:

oop

haskell

Well, I do recognized I'm puzzled with haskell and that this is my first weekend with it.

I just wonder if the following design of a OO-class Point2D

UML design of Point2D

is supposed to be written in Haskell as follows:

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

Yes, I know I should not try do "think OOP" in Haskell, but ... well, 1) that's going to take a long time, and 2) in practice I guess you're gonna find several OOP designs to be rewriten in Haskell

like image 896
cibercitizen1 Avatar asked Dec 01 '13 22:12

cibercitizen1


People also ask

Can you do OOP in Haskell?

Haskell isn't an object-oriented language. All of the functionality built here from scratch already exists in a much more powerful form, using Haskell's type system.

How do you define a class in Haskell?

Haskell also supports a notion of class extension. For example, we may wish to define a class Ord which inherits all of the operations in Eq, but in addition has a set of comparison operations and minimum and maximum functions: class (Eq a) => Ord a where. (<), (<=), (>=), (>) :: a -> a -> Bool. max, min :: a -> a -> a.

What is it called when the type of a function contains one or more class constraints Haskell?

Overloaded Functions. A polymorphic function is called overloaded if its type contains one or more class constraints. (+) :: Num a ⇒ a -> a -> a.

What is instance Haskell?

An instance of a class is an individual object which belongs to that class. In Haskell, the class system is (roughly speaking) a way to group similar types. (This is the reason we call them "type classes"). An instance of a class is an individual type which belongs to that class.


2 Answers

First off: indeed, you should try not to "think OOP" in Haskell!

But your code isn't really OOP at all. It would be OO if you started to try virtual inheritance etc., but in this example it's more that the OO implementation happens to resemble the obvious Haskell implementation.

Only, it should be emphasised that the type class PointFamily really doesn't have any particular 1:1 relation with the data type Point2D, like their bundling in the OO class. You would in practise make instances of this class for any type where it conceivably works. Unsurprisingly, all of this has been done before; the most widespread equivalent of PointFamily is AffineSpace from the vector-spaces package. That is a lot more general, but has in principle much the same purpose.

like image 161
leftaroundabout Avatar answered Oct 28 '22 06:10

leftaroundabout


Just to illustrate leftroundabout's point about not needing to think OO, I took the liberty of removing the typeclass, to show how straightforward the code can be. Don't vote for this if you currently need the ability to write code that works unmodified against 2D and 3D points. But I suspect what you really need right now is a 2D point and this code does that nicely. This is on the "You ain't gonna need it" principle. If, later, it turns out you do need it, there are several ways of introducing it.

I also added bang patterns on the x and y fields, since typical 2D applications usually want those fields to be strict.

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
like image 21
GarethR Avatar answered Oct 28 '22 05:10

GarethR