Why Haskell?

Last Edited: 6/10/2024

I am writing this blog for me to come back at this and re-convince myself to continue learning Haskell.

Haskell & Haskell Curry

Haskell, named after the famous logician Haskell Curry, who made significant contributions to the inception of functional programming, is a pure functional programming language based on lambda calculus. Haskell has various characteristics that object-oriented programming languages (such as C, Python, and Java) do not necessarily have, making it a suitable tool for certain sets of problems.

Pure Functions

As the name “purely functional” suggests, functions in Haskell are meant to be pure, meaning that they should produce the same output for the same input without changing external states or producing side effects. To understand what this means exactly and why it is important, let’s look at an example of an impure function that modifies inputs and produces side effects.

counter = 0
 
def hello(names: List[string]):
    last_person = names.pop()
    counter += 1
    if counter == 100:
     return f'Hello, {name}! You are 100th customer!'
    return f'Hello, {name}!'
 
hello(['Alice', 'Bob'])
# => 'Hello, Bob!'

The above function says hello to the last person in the list. However, the function also accidentally removes the last person from the list with the pop function (modifying the input) and increments counter while saying hello to the last person in the list (side effect). Also, if the counter is 100, it celebrates the fact that that person is the 100th customer. In a small codebase, dealing with this kind of function might not be hard, but in a large one, it becomes extremely difficult to keep track of the modifications and side effects.

names = ['Alice', 'Bob']
hello(names) # => Hello, Bob!, names=['Alice']
hello(names) # => Hello, Alice!, names=[]
hello(names) # => Err!

You can see why this might be problematic by looking at the above. The output from the function produces different results and updates counter without any clear indication, which can be super confusing when using this function elsewhere. Impure functions can be a headache for unit tests too, as we need to test functions with different combinations of inputs and external states. If the functions were pure, we could simply test the functions with different inputs and see if they work as expected. Same goes for co-current operations. As shown above, Haskell’s approach to pure functions can improve reliability, scalability, testability, and readability, and is preferred in many academic and industry scenarios.

Lazy Evaluation

Haskell’s uniqueness also lies in lazy evaluation, where computation is done only when needed. The opposite is strict evaluation, used in many languages like Python, Java, and Ruby, where computation is performed in order regardless of whether it is necessary for deriving the output or not. To understand this, let’s look at an example.

def example(arg):
    x = func1(arg)
    y = func2(arg)
    z = func3(arg)
    if z:
     return x
    else:
     return y

In a strictly evaluated language, x, y, and z are all evaluated before moving to the if statement. If each of them takes 10 seconds, it takes 30 seconds before moving to the if statement. On the other hand, a lazily evaluated language like Haskell evaluates z first and then determines whether to evaluate x or y. If each of them takes 10 seconds, it takes 20 seconds instead of 30 seconds.

Skill Issue?

Now, I can see you reading this and screaming “Skill issue!” from the top of your lungs. Yes, you can write pure functions in object-oriented programming languages as well and avoid having to evaluate all variables in all cases. You can refactor the above functions to the following:

def hello(names: List[string], counter: int):
    if counter == 100:
      return f'Hello, {names[-1]}! You are 100th customer!'
    return f'Hello, {names[-1]}'
 
def example(arg):
   z = func3(arg)
   if z:
    return func1(arg)
   else:
    return func2(arg)

After all, all established programming languages are virtually Turing-complete. However, the point is that functional programming languages do not permit impure functions and allow lazy evaluation by default, which can relieve you from always being stressed about unintentionally writing functions with unexpected behaviors, side effects, and unnecessary evaluations. In some situations, ensuring these things are super important, which makes Haskell a valuable tool.

Production

I explained some of Haskell’s unique features that can describe why it might be preferred in some situations. Aside from the above, Haskell is also a declarative language that can make code more readable, and it has the Hindley-Milner type system and is statically typed (can detect type errors at compile time), which allows for powerful type inference and polymorphism.(Super Important) If you want to know more about it, google “declarative vs imperative languages” and “Haskell type system” respectively.

What’s more great about Haskell is that it is already proven to be a production-ready language with various academic and industrial applications. Meta used Haskell to build a performant spam filter, GitHub implemented Semantic with Haskell, Microsoft built Bond using Haskell, and the list goes on. The tooling has been consistently improving thanks to amazing Haskell enthusiasts around the world.

Be Different

Despite Haskell's numerous advantages, it remains relatively unpopular, ranking 29th in the TIOBE index, which assesses the popularity of programming languages, and making up only 0.132% of active users on the GitHub source code repository in 2024. This means that if you become a master of Haskell, you will possess a rare and unique skill in an overly saturated developer world. (100% my personal opinion) It is also intellectually satisfying and meaningful to learn functional programming after getting used to object-oriented programming, as it often requires a different thought process in tackling the same problem.

Conclusion

Whether you should learn Haskell or not depends entirely on you and your situation (problem with immutable data exists), but I personally would like to recommend learning this language. As I have just started learning Haskell, I hope that I can become a better developer with Haskell in my toolbox.

Resources