As a newly started company, we have a lot of technical decisions to make. One of the important ones is the choice of a programming language. Since we’re building a web application, this goes for both the client (i.e. the web browser) and the server.
However, there was another option. Two of us (me and Sebas) are enrolled in the Software Technology master program at Utrecht University, where we often use the programming language Haskell. Haskell is a functional programming language, which means that a program is composed of expressions instead of statements, as is the case in an imperative programming language.
As you might have guessed from the title of this post, we decided to use Haskell for our server side programming. What are the features that made us choose Haskell?
First, we like the functional programming model. Modeling programs based on what values are, instead of what bits to move where, is much closer to the way we think. We write down what we mean, and let the compiler figure out how to calculate it. This also leads to shorter code: Haskell is often surprisingly concise.
Another important consideration is the strong type system that Haskell has. It has powerful features that prevent you from running incorrect programs, while not getting in the way, as is often the case in traditional statically typed languages like Java or C#. This is due to the fact that Haskell has type inference: it can deduce the types of variables and functions without programmer specifications.
Something that sets Haskell apart from almost all other programming languages, is its purity: an expression in Haskell is not allowed to do anything on evaluation other than return its value (functions are not allowed to have side-effects). This has many implications. For example, data is immutable: if you modify a list, for example, you create a new copy (although smart compilers share duplicate parts for efficiency). This means that you never have to think about other parts of the code changing your data: you can always reason locally. Another implication is that your language can be lazy (and in fact, Haskell is). This means that expressions are not evaluated unless their results are needed. This can lead to performance improvements, and allows you to use infinite data structures.
If we disallow side effects, how do we perform I/O, for example? Haskell uses an abstraction called a monad to do this. A monad shows up in the type, indicating that we are performing side effects. The I/O monad allows us to force an ordering on actions, allowing us to safely perform the actions in a lazy setting. We can also use monads to keep state, have mutable variables, and many other things.
Purity also makes concurrency a lot easier: if data is immutable, there is no risk in sharing it between different threads. If you need to share mutable data between different threads, Haskell offers a few ways of dealing with this, the most interesting of which is software transactional memory (STM), a lock-free way of building composable atomic actions.
Since Haskell is a functional language, functions are first class: you can create them on the fly, pass them as arguments, return them as results, store them in a data structure, etc. This allows you to easily create powerful abstractions. For example, one often-used Haskell function is map. It takes an argument that turns a value of type a into a value of type b, and uses this to transform a list of a’s into a list of b’s by applying it to each element. This function abstracts away looping over a list. In a similar way we can create our own abstractions. This often leads to the creation of lightweight EDSLs (embedded domain specific languages), especially since Haskell allows the creation of (infix) operators as well.
The combination of conciseness, locality of data, strong types and explicit side-effects has a very important consequence: it makes refactoring easy and risk-free. You can change your code, and if it still type checks, you can often be sure that it still works. Combined with the power of abstraction this means we can quickly develop programs that can be easily understood and modified by others.
Finally, another positive aspect of Haskell is its community. There is an active blog community, a large and helpful IRC channel (#haskell) and an online package repository. There is an industrial strength compiler, a dependency tracking package manager and built-in tools like code coverage.
Of course, there are also a few risks involved in choosing a language like Haskell. Since it doesn’t have a user base as large as some other languages, there are less libraries available. This is alleviated in part by a strong C interface that Haskell provides. Because of laziness, performance problems can be harder to diagnose and fix. And of course, there are less programmers who have experience with Haskell, so finding people to help you can be harder.
But all in all, we feel that the benefits Haskell can bring us outweigh the risks. And most of all, Haskell makes programming fun!