This page is an attempt to compare typical constructs in the functional style to more-or-less equivalent constructs in the imperative style. Some of the "equivalence" is glossed over. Naturally, both paradigms (and the languages used below) have capabilities that are under-represented by these examples. ---- HaskellLanguage: data type data Position = Position { px, py :: Double } CeePlusPlus: struct or class struct Position { double _x, _y; Position(double x,double y) : _x(x), _y(y) { } } ---- HaskellLanguage: type alias type Line = (Position, Position) CeePlusPlus: typedef typedef pair Line; ---- HaskellLanguage: function dotProduct :: Vector -> Vector -> Double dotProduct vector1 vector2 = ((vx vector1) * (vx vector2)) + ((vy vector1) * (vy vector2)) CeePlusPlus: function double dotProduct(Vector vector1, Vector vector2) { return (vector1._x * vector2._x) + (vector1._y * vector2._y); } ---- HaskellLanguage: algebraic data type data Shape = Circle { circle_center :: Position, circle_radius :: Double } | Square { square_origin :: Position, square_size :: Double } shapeCenter :: Shape -> Position shapeCenter (Circle center radius) = center shapeCenter (Square origin size) = positionMove origin offset where offset = Vector size/2 size/2 CeePlusPlus: abstract base class struct Shape { virtual Position center() = 0; } struct Circle : public Shape { Position _center; double _radius; Circle(Position center, double radius) : _center(center), _radius(radius) { } virtual Position center() { return _center; } } struct Square : public Shape { Position _origin; double _size; Square(Position origin, double size) : _origin(origin), _size(size) { } virtual Position center() { Vector offset(_size/2,_size/2); return _origin.move(offset); } } ---- HaskellLanguage: List data type data List a = Empty''''''List | List''''''Node { first :: a, rest :: List a } headList :: List a -> a headList Empty''''''List = error "can't take the head of an empty list" headList List''''''Node first rest = first tailList :: List a -> List a tailList Empty''''''List = error "can't take the tail of an empty list" tailList List''''''Node first rest = rest lengthList : List a -> Int lengthList Empty''''''List = 0 lengthList List''''''Node first rest = 1 + lengthList rest CeePlusPlus: translation of the List data type template struct List { virtual A head() = 0; virtual List& tail() = 0; virtual int length() = 0; } template struct Empty''''''List : public List { virtual A head() { throw exception("can't take the head of an empty list"); } virtual List& tail() { throw exception("can't take the tail of an empty list"); } virtual int length() { return 0; } } template struct List''''''Node : public List { A _first; List& _rest; List''''''Node(A first,List& rest) : _first(first), _rest(rest) { } virtual A head() { return _first; } virtual List& tail() { return _rest; } virtual int length() { return 1 + _rest.length(); } } ---- More to come (this page is a work in progress). Feel free to add your own examples. ''I think that trying to compare algebraic data types to object-oriented classes is missing out on an important distinction. In languages like C++ and Java, objects contain both data and code, intermingled freely. By contrast, Haskell enforces a much stricter separation; algebraic data types may contain only data and no methods. (The accessor methods used above are merely syntactic sugar--they are, and could easily be defined as, standalone functions.) In this respect, they are much closer to Pascal's variant record types than they are to classes.'' ''Similarly, features like abstract data types and advanced polymorphism are provided by typeclasses; in their simplest form, these play a role much like Java's interfaces. They are allowed to contain method signatures (and, unlike Java, default implementations) but no data.'' Since in Haskell functions are data, data structures ''do'' contain code. This puts Haskell's records quite close to Java's interfaces, while Java doesn't really have an equivalent for typeclasses. Subtype relations are also different and hard to compare. *Actually, TypeClasses serve the role of ''interfaces'' in the Java sense. Declaring a type as an instance of a typeclass implies that the said type supports that particular interface. On that point - if you are going to make this comparison, then since Haskell functions are data, the C++ equivalent would more properly be defined as a FunctionObject (more specifically, see StlFunctionObjects), something like: struct D''''''otProduct { double operator() (const Vector &vector1, const Vector &vector2) const { return (vector1._x * vector2._x) + (vector1._y * vector2._y); } }; Only if Dot''''''Product is a friend of Vector, and then, why bother? Just write it as a normal function. Remember, the distinction between ADTs and objects is only from which side of the (method,type) matrix you're looking at things. ---- CategoryFunctionalProgramming RosettaStone ProgrammingChrestomathy