Playing with Elixir

Well I did a crap job about keeping up with this blog. Almost 5 months have gone by… I haven’t been doing nothing, though. I have been refactoring a CLI framework written in node that I started many months ago. But the past few days I have really been distracted by Elixir.

Im a complete n00b with functional programming so it has really been a major shift. But after a couple hours of messing around in iex and reading the docs I decided to dive right in.

I decided that I was going to attempt to copy all of the Array methods from Underscore.js and create a Elixir module to be used with Lists. I am fully aware of the List module, but that’s not the point. I wanted to try to recreate the functionality in these methods using only basic Elixir code, pattern matching and a whole lot of recursion. Even though Elixir has case, cond and if I wanted to focus on pattern matching (the concept that pulled me into Elixir).

So far I have the first 4 Array methods from Underscore.js first, initial, rest, compact as well as two helper functions reverse and length. You can see my progress here as I continue to add functions, a readme and some tests. I won’t go into all of these but I do want to go into the one I had the most difficulty with: initial. And Hey! I’ve only been messing with Elixir (and FP) for 3 days, so thats allowed. Feel free to stop reading this post now.

Linked Lists

Coming from a Javascript background I think of Arrays when I think of linked lists (even though I should think of tuples ). Lists in FP are similar to Arrays in Object Oriented languages, in that they are well… lists with multiple values. However Arrays in Javascript, for example, are still Objects, and they inherit the Array prototype, so you get all sorts of helpful properties and methods that make manipulating the array and retrieving information about the array much easier.

You don’t get that in Elixir or really any other functional programming language. You can use the List module that comes with Elixir, but that’s no good for learning functional programming.

A linked list is basically a value taking up a chunk of memory, pointing to the next value taking up a chunk of memory, pointing to the next chunk of memory, until the last value does’t point anywhere else. So when you have a list, you really only know what the first element (also known as head) of the list is. Keep that in mind as I review the initial function.

Initial

If you are not familiar with the initial method in Underscore, here is the definition:

Returns everything but the last entry of the list. Passing n will return all the values in the list, excluding the last N.

Ok. Onward.

The first two functions are the public functions of my Underscore module

def initial(list, n) do
  do_initial list, n
end

def initial(list) do
  do_initial list
end

Notice how they bot have the same name. In Elixir the first function is actually called initial/2 and the second is called initial/1, where the appropriate function is called depending on the number of arguments being passed in. I’ll take this simplicity over an if/else block any day.

To test my function I open iex and run iex> Underscore.initial([1,2,3,4,5]). (And because I am an amazing developer, it returns 1.) Before 1 is returned, initial takes the input and passes it on to the do_initial private functions (notice defp).

defp do_initial([]) do
  nil
end

defp do_initial(list) do
  [head | tail] = reverse list
  reverse(tail)
end

But wait, there are two functions now with the same name, and same arity. This is where pattern matching really comes into play. All Elixir wants is peace and balance, so from many aspects of that language it is just try to match patterns to attain that balance. The first function listed does only take one argument but pattern matching allows us to check for an empty list. So the list will only be passed in if its empty.

So upon calling Underscore.initial([1,2,3,4,5]) the list gets passed to:

defp do_initial(list) do
  [head | tail] = reverse list
  reverse(tail)
end

Two new variables are created inside the function, head and tail which are then equated to the list after it has been passed through the reverse function. As I said earlier, Elixir only knows the first element of a List, and in initial we want a new list with some stuff knocked off the end. That in addition to the fact that Elixir wants to balance the equation [head|tail] = [5,4,3,2,1], the only outcome could be head which would be return to 5 and tail which would return [4,3,2,1], the remainder of the list. I then reverse tail in order to return a new list where the last element has been removed: [1,2,3,4].

I also added the initial/1 function with a condition to catch empty lists. Elixir throws and error when you try to get the head or tail of an empty list so I decided to return a falsey value, in this case nil.

defp do_initial([]) do
  nil
end

In the case that we wanted to get a new copy of the list without the last n elements we would call: Underscore.initial([1,2,3,4,5], 2). And yet again do to my special set of skills, we get [1,2,3].

The initial/2 function passes on list and n to:

defp do_initial(list, n) do
  [head | tail] = reverse list
  do_initial reverse(tail), n - 1
end

Hear, head and tail are created from the reversed list and then do_initial calls itself passing in reversed tail and a number 1 less than n. This will continue until some other pattern is matched. head and tail are created from the new, shorter, reversed list and then do_initial calls itself again.

Because this function is recursive we need function that will stop the recursion and return the value we actually want.

defp do_initial(list, 0) do
  list
end

When the second parameter is equal to zero, do_inital/2 returns our new list that is missing the last n elements.

Success!