This post is targeted towards all those Elm developers (and functional programmers in general) who are curious about Haskell and would like to learn how what they already know and love from Elm maps directly to Haskell.

Also, since Haskell's feature set and syntax are wider than Elm's, of course I'll need to try and fill the gaps and explain certain things that just do not exist in Elm. 😉

If this first post gets enough attention, I might consider adding more follow up posts and turn this into a series (hopefully).

Let's talk about Functors!

If you have ever seen Haskell code before, you can really tell it has greatly influenced Elm syntax, one of the biggest differences is that in Haskell type declarations are preceded by ::, whereas in Elm only by :.

Another big difference is that in Haskell there is a concept called typeclasses, which we can explain more or less saying that they group a class of types and help us define interfaces that a certain data type need to fulfil to be considered "an instance of that specific typeclass".

For example, the Functor typeclass in Haskell is defined like this:

This typeclass declaration in Haskell just means that for a general type f, it will "be a Functor" if it has a map function. As you can see, any map function (or fmap) needs to have the signature (a -> b) -> f a -> f b. More accurately, we can say that any custom type that implements a function with this type signature does have an instance of the Functor typeclass.

I probably do not need to explain what the (f)map function does, as you are already using Functors in Elm every single day! 🤯 To list some of them: List, Maybe, Result, Dict, Task, etc...

Why is that typeclass called Functor instead of Mappable? 🤷🏼‍♂️

Why is this important? Well, I think one of the design decisions for Elm was to be simple from the beginning and not bother people with buzzwords, just let them use the code and gain intuition about how things work and that will do. But unfortunately if we want to learn Haskell after Elm we need to start putting random names on things! 😉

Infix operators are nice, actually

Yet another big difference between Haskell and Elm is obviously Haskellers love for infix operators. For example, instead of using fmap you could use the <$> operator. Consider the following mundane Elm code:

This would be possible to write in many different styles in Haskell:

fmap (*2) [1..4]    -- > [2,4,6,8]
map (*2) [1..4]     -- > [2,4,6,8]
(*2) <$> [1..4]     -- > [2,4,6,8]
[1..4] <&> (*2)     -- > [2,4,6,8]
(*2) `fmap` [1..4]  -- > [2,4,6,8]
(*2) `map` [1..4]   -- > [2,4,6,8]

There are quite a few things to learn from this snippet alone:

  1. Notice that map is just a more specific implementation of fmap that in Haskell only works with Lists!
  2. In Haskell we have some nice syntax sugar for ranges of things, where [1..4] is equivalent to List.range 1 4 in Elm.
  3. It is easier to work with infix operators and partially applied functions in Haskell generally speaking, where adding a parameter to either side of the operator would mean completely different things if that operation is not commutative (2^ vs ^2).