I remember an interview questions from one of my employers. It was about 3 things which define Object Oriented Programming. Expected answer was: Encapsulation, Inheritance, and Polymorphism... Well Haskell is NOT an OO language. It supports encapsulation, it has sophisticated inheritance concept called type classes, and it supports polymorphism in ways an OO language could not even dream about. I guess programming is changing, questions and aswers need to change too.
In my learning Functional Programming and Haskell in particular, the most surprising and unexpected eureka moments have all been related to polymorphism.
Functional world offers polymorphism and code reuse in places which are unexpected to an OO programmer (or, at least, unexpected to me). I blogged about code reuse and for-loops (for example: this curly braces post), but that was just scratching the surface.
Consider these examples of functionality you may need to code:
1) Lists viewed as non-deterministic computations: normal computing deals with one value, non-deterministic computing deals with a (discrete/finite) collection of possible values.
The result of operating on several values is typically even bigger collection of different possibilities.
Examples: If a = [1,2,3,4,5,6] represents result of tossing one die,
b =[2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 12] could represent possible sums of tossing two dice. (You may be tempted to write something along the lines of b=a+a.) Also, if you very ambitious you could combine the same values and add probabilities for another good example... but I do not go there.
2) Lists viewed as 'vectors': If we want to add two lists we would add corresponding coordinates forming a vector of the same size. This is the most straightforward view of the 'list' concept.
Zip functions are based on this approach.
3) Maybe concept (Option in SCALA). This concept provides better alternative to null values in traditional languages. You want a type which encapsulates having a value or having Nothing.
4) Improving on Exceptions. If you want something better that exception throwing supported by various OO languages you may want to decide to invent something like the Either type: which can be either right (a result) or left (error).
5) Function Composition. .. if you remember enough math to know what it is ;)
The above list can be made longer. But just these 5 concepts should look like apples and oranges, and some Pepperoni, a Car, and a color Blue. Could you ever envision an OO program designed to handle ALL of the above concepts in the same way? There are many huhh moments in learning functional programming, but this is what makes it so fascinating.
Yes, the above concepts are all very much related in some very deep ways. These deep ways are:
- they all can be made into applicative functors
- they all can be made into monads
These similarities (or, to be more accurate, this similarity because being a monad implies being applicative functor) allows Haskell programmers to write the same code accross all of these 5 concepts (and many concepts not listed here). To me this is a whow! No, it is: a big WHOW!
So I will try to write a bit more about it in the future.