A functional choice

To begin a story, a while back, I wanted to learn a functional programming language. I wanted to find out just how different the functional paradigm is to the imperative paradigm. Previously the closest I got to functional programming came from JavaScript, and I’ve always found it so much more powerful to pass functions around than to limit myself to more procedural means. That being said, JavaScript isn’t a functional language, it’s just the closest I got at the time.

So, I was advised by a colleague to try Haskell.

Haskell being a pure functional language; isn’t diluted in anyway. It hasn’t been bastardised to allow for multiple paradigms, which is what makes it such a good entry point into functional programming. You have to adopt a functional mindset to work with Haskell, you can't partially apply the mindset, or dip your toes in, it's all or nothing.

Haskell employs all common features seen in the biggest functional languages such as: pattern matching, list comprehension, type classes etc... Also, since language researchers created Haskell, it has many features that are rare in other functional languages (such as lazy evaluation). Haskell doesn't have side effects, unlike languages that support imperative paradigms. However that does have it's own drawbacks, mostly in flexibility.

I found Haskell great fun to learn. Especially when I came across such a great resource learnyouahaskell.com.

But I’m not here to sell Haskell, that's not my intention here. In fact, I'm looking for something else. I'm looking for something which I feel is much more approachable for everyday use.

Why not stick with Haskell?

I'm just not finding much use for Haskell, day to day. Many purely functional languages suffer from this very same thing. The functional paradigm isn't best suited to solve every problem, which is fine! But it doesn't even feel suitable for most, which is disappointing. I couldn't imagine building a large application in Haskell. That's not because I think it isn't performant, or that I think the code would be unmaintainable, on the contrary. But it doesn't have enough infrastructure, tooling or community around it to support every day applications. I get the impression that Haskell is still primarily used for academic purposes. Many of the other functional languages live on well-supported platforms and allow interop with the other languages on that platform.

I don't dislike Haskell by any means; it's actually frustrating that I can't find much use for it.

I want to pick up a language which I feel I can find more everyday use cases. One which will rival C# and JavaScript for usage (okay, maybe not JavaScript since that's everywhere). To do this, it will most likely need to be more than just a pure functional language, and it must be possible to take advantage of well-established libraries/frameworks.

Options

There are many, of course. But I’m going to highlight a few that interest me personally and talk about some of the features that excite me most about the language.
Just to show some sample syntax, for each language I'll write a function to return the nth number in the Fibonacci sequence - massive cliché, I know. But it will be short and should require a brief showcase of the languages syntax. Here's Haskell's:

# Haskell Fibonacci
fib :: (Num a, Eq a, Num b) => a -> b
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

F-Sharp

  • .NET platform
  • Multi-Paradigm (Functional and OO)
  • Great tooling, debugging and error checking.
  • Seamless interop with .NET libraries

With F# supporting imperative features as well as functional, it makes F# much more of an all rounder. F# is a child of OCaml, so the syntax is very similar.

It's pretty uncommon for functional languages to have such a good development story as F# has. Debugging, intellisense etc; is a rare thing. So this is a big plus for F#.
I have to admit, the main benefit I see of learning F# over the other choices, would be that I already do a lot of work on the Microsoft stack. I'm already very familiar with .NET, it's libraries and tooling. I'm struggling to find anything new in F# that stands out to me, as C# has adopted many of F#'s feature set.

// F# Fibonacci
let rec fib n =
    match n with
    | 1 | 2 -> 1
    | n -> fib(n-1) + fib(n-2)

Elixir

  • Erlang VM
  • Interops with Erlang code
  • New kid on the block - how is the community?
  • Highly scalable (concurrent)
  • Great fault-tolerance support
  • Macro system, new code can actually be injected into a running system

I've always been intrigued by Erlang. Given the purpose of its inception. It's definitely not the most approachable language, and this is what Elixir promises to remedy (no pun intended). Here are a couple of features that interest me about Elixir.

Actor concurrency

Elixir uses the Actor Model as the foundation for it's concurrency.
At the basic level, an actor is a process which executes a function.
In Elixir you can think of an actor similar to an object - an object with a mailbox and some functionality. An actor can talk to other actors by means of messages. These processes are completely independent, they don't share state with one another. If an actor needs data, it is passed in through messages. This way we avoid problems such as the lost-update problem typically found in threaded concurrency models.

Don't confuse these processes with heavy OS processes or system threads. These are very lightweight and a single machine is capable of running hundreds of thousands of processes without breaking a sweat.

Processes in Elixir support intra-process communication via message passing. Together, these features make up the Actor Model that Erlang is highly recognized for using. Let's face it, any model of computation which is inspired by general relativity and quantum mechanics has got to be worth a look right?

An actor mailbox is much like a standard message queue - each process has a mailbox to which a handler function will attempt to pattern match against the messages; consuming any message that matches the pattern.

It's also worth noting that these actors don't have to be on the same machine, they can be completely separate - which makes Elixir systems easily distributable.

Fault-tolerance

To cope with failures, Elixir provides supervisors which describe how to restart parts of your system when things go awry, going back to a known initial state that is guaranteed to work. Pretty cool.

# Elixir Fibonacci
defmodule Fibonacci do
	def fib(0), do: 0
	def fib(1), do: 1
	def fib(n), do: fib(n-2) + fib(n-1)
end

Clojure

  • Runs on the JVM
  • Interops with Java
  • A Lisp
  • Advertises as a general-purpose language with a functional focus
  • Can be used on the front end
  • Macro system

Lisp syntax

Without really digging into this, I’m not going to treat this as a pro for Clojure. I get the impression people either love or hate the Lisp syntax, and my first impressions aren't positive. Either way, I’m certainly intrigued. Here’s an example of Clojure's syntax comparing it to Java.

// Java
public void hello(String name) {
    System.out.println("Hello, " + name);
}

; Clojure
(defn hello [name]
  (println "Hello," name))

Software transactional memory

Clojure transactions should be easy to understand if you've ever used database transactions, it's essentially the same thing in Clojure. STM ensures that all actions on references are atomic, consistent, and isolated. Atomic means that every change to references made within a transaction occurs or none do. Consistent means that each new value can be checked with a validator function before allowing the transaction to commit. Isolated means that no transaction sees the effects of any other transaction while it is running. Another feature common to STMs is that, should a transaction have a conflict while running, it is automatically retried; which is handy.

Dynamic polymorphism

Also known as runtime polymorphism, is a feature Clojure seems proud of. It is achieved by using what Clojure calls multimethods.
Essentially we define a function using the defmulti keyword, giving it a name and a signature (kind of like you would a delegate in .NET). Then, we can use the defmethod to provide what is essentially overloads to the defmulti interface you just defined.

The following code example stolen from Clojure.org shows how it works quite well:

(defmulti encounter (fn [x y] [(:Species x) (:Species y)]))
(defmethod encounter [:Bunny :Lion] [b l] :run-away)
(defmethod encounter [:Lion :Bunny] [l b] :eat)
(defmethod encounter [:Lion :Lion] [l1 l2] :fight)
(defmethod encounter [:Bunny :Bunny] [b1 b2] :mate)
(def b1 {:Species :Bunny :other :stuff})
(def b2 {:Species :Bunny :other :stuff})
(def l1 {:Species :Lion :other :stuff})
(def l2 {:Species :Lion :other :stuff})
(encounter b1 b2)
-> :mate
(encounter b1 l1)
-> :run-away
(encounter l1 b1)
-> :eat
(encounter l1 l2)
-> :fight
; Clojure Fibonacci
 (defn fib3 [n] 
  (take n 
    (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))

To sum up

The features I have mentioned in this post are ones that interest me most about the language. My main concern is that will I swap out Haskell for a language that is in the very same boat I’m attempting to leave? One with a very small community, tooling, etc…

  • F# - Arguably the most natural fit and probably easiest of the 3 to get started with, since I’m much more familiar with the platform than the other 2. Then again, the biggest reason I see for not going down the F# route is just that - explore something new?
  • Elixir - I must admit, after doing a little research into these 3 languages, it's Elixir that intrigues me the most. Even if Erlang is scary, it's unlike any language I’ve seen before mixed with the best bits of those I have. However, I get a feeling that even with the nicety Elixir brings over Erlang, it's still a language used to build really stable; highly concurrent systems which may ultimately complicate it's usage for the more simple systems.
  • Clojure - I've never worked with any language on the JVM before, which could be valuable. Being able to easily interop with libraries and frameworks wrote in Java is a massive advantage as an 'all rounder'. However, I’m not sure what to think of the Lisp syntax. Clojure does seem more 'general purpose' - than Elixir certainly, to which it only competes with F# in that regard.

I guess in the end one of 2 things will happen: My choice will be made when I need to use one of these languages because of their strengths. Or I will wake up one morning and think "I fancy having a go at that today", most likely the latter.