July 24th, 2015
(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: firstname.lastname@example.org
I like this article, but it does confuse Functional Programming with static data types. Consider this example of evil Ruby code:
Take for instance the following Ruby code that uses Virtus.class Events < Array def <<(event) super(event.is_a?(Hash) ? construct_event(event) : event) end def construct_event(hash) hash.key?(:emails) ? EmailEvent.new(hash) : Event.new(hash) end end
Recently I spent hours debugging this code where the append (<<) method was called with a Virtus object (unexpected) instead of a hash (expected). After consulting a seasoned Ruby developer, I learned that this is a so-called known behavior in which Virtus would perform its ‘magic’ under the hood (no pun intended) when an object is initialized. Because of this unexpected behavior, we had to compensate for it by putting in place a conditional so it would handle an object or a hash accordingly. It’s exactly this kind of magic that FP tries to avoid, as demonstrated by the following equivalent Haskell code.
The Haskell code is then statically typed. I love the Functional Paradigm, but we should be careful about confusing it with statically typed programming. Immutability is not the same static typing. A language like Clojure is mostly Functional, but allows us to add in our data-type correctness in a gradual manner.
I do like this bit about the important of algebraic data types (ADT) :
Correctness in functional languages isn’t merely a function of immutability, it also has to do with the fact that most of them support algebraic data types (ADT) and advanced type systems.
Let’s start with ADT. In a typical type system found in mainstream languages like Java, C# and Objective-C, you can easily create types that combine other types either via composition (C is composed of A and B) or inheritance (B:A and C:A). This is called conjunction. Where it falls short is a succinct way of expressing disjunction, e.g. A = B | C where B <> C. That’s where ADT comes in handy.