What do standard OOP patterns look like in Haskell?

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com


Most software developers are familiar with the OOP motto “everything is an object.” People accustomed to C++ classes often find the Haskell concept of type classes difficult to grasp. Why is it so different?

C++ classes pack functions together with data, which makes it convenient to represent and consume data. Use of interfaces (abstract classes) allow classes to interact by contract, instead of directly manipulating the data in the other class. There exist alternative ways in C++ to accomplish such functionality (function pointers, discriminated unions), yet these techniques are not as handy as classes. Classes are also the primary way to hiding implementation details. Moreover, classes represent a handy way to group related functionality together. It’s extremely useful to browse the structure of large C++ project in terms of classes instead of individual functions.

Haskell provides other solutions for these problems.

1.1 Type with several representations: use algebraic data type (ADT)
For the types with different representations, algebraic data types (ADT) – an analog of discriminated unions – are supported:

data Point = FloatPoint Float Float
| IntPoint Int Int
Haskell provides a very easy way to build/analyze them:

coord :: Point -> (Float, Float)
coord (FloatPoint x y) = (x,y)
coord (IntPoint x y) = (realToFrac x, realToFrac y)

main = do print (coord (FloatPoint 1 2))
print (coord (IntPoint 1 2))
So ADTs in general are preferred in Haskell over the class-based solution of the same problem:

class Point a where
coord :: a -> (Float, Float)

data FloatPoint = FloatPoint Float Float
instance Point FloatPoint where
coord (FloatPoint x y) = (x,y)

data IntPoint = IntPoint Int Int
instance Point IntPoint where
coord (IntPoint x y) = (realToFrac x, realToFrac y)

The equivalent C++ implementation using inheritance requires much more machinery than our 5 line, ADT-based solution. This also illustrates a Haskell benefit–it’s much easier to define types/functions. Perhaps objects are not as great as you thought before. :D

using namespace std;

ostream & operator<<(ostream & lhs, pair const& rhs) {
return lhs << "(" << rhs.first << "," << rhs.second << ")";

struct Point {
virtual pair coord() = 0;

struct FloatPoint : Point {
float x, y;
FloatPoint (float _x, float _y) : x(_x), y(_y) {}
pair coord() {return make_pair(x,y); }

struct IntPoint : Point {
int x, y;
IntPoint (int _x, int _y) : x(_x), y(_y) {}
pair coord() { return make_pair(x,y); }

int main () {
cout << FloatPoint(1,2).coord();
cout << IntPoint(1,2).coord();
return 0;
As you see, ADTs together with type inference make Haskell programs about 2 times smaller than their C++ equivalent.