At the Lone Star Ruby Conference, Dave Thomas talked about Elixir to everyone. I found it kindof interesting that there were no loops and the use of
if was discouraged. It was neat to see that everything was idempotent and that pattern matching made certain problems incredibly easy to solve with very little code.
So when I found exercism.io and saw that they had an Elixir track, I jumped on it. What I’ve noticed is that solving problems in a functional way changes the way that I code in an OO language. It doesn’t mean I want everything to be a function and never have state, but I want each method on an object to have no side effects and to require an absolute minimum of internal state to function.
Let’s look at some examples from the Exercism Elixir track.
The Fibonacci sequence is an oft-asked puzzle question since it requires knowledge of recursion and proper branching conditions. In Elixir, it breaks down very simply because of pattern matching.
1 2 3 4 5
Since Elixir looks for the first match when a function is called,
Fib.fib(1) matches line 3, and
Fib.fib(2) matches line 4, which calls
fib(1) + fib(0) which then match lines 2 and 3. Impressive, no?
Guards allow you to pattern match based on a property of the values being passed to the function. This lets you test the types without having to have branches inside your function. There are only a few expressions that can be used as guards.
1 2 3 4 5 6 7 8 9
This allows you to have a single interface for Lists, Binarys, Bitstrings and Tuples, even if the logic for each one is quite different. Since they’re all separated, it becomes very easy to maintain..
Cond is an interesting construct, similar to case, but without an initial argument. It is more like saying
case true …. As a result, it’s very easy to pattern match on anything.
1 2 3 4 5 6 7 8 9 10 11 12
Since it’s really common to work on the result of one function in another function, but you don’t have objects which keep internal state, Elixir and Erlang have the idea of pipelining.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Pipelining is really just a shorthand for passing the result of one function in as the first argument for the next function. As you can see on line 3, this makes it very easy to read the order in which you would think of things. “Take a sentence, normalize it, find the words in it, count the words you found.”. The other way to write this would be
count_words(find_words(normalize(sentence))). It works, but it’s harder to read and you end up with lots of right-parens.
While there’s nothing super special about this, I have found it very useful for readability, and that’s a huge part of programming.
Binarys, Strings and Lists - Oh My.
One of the most confusing things about Elixir (and Erlang) when I started off is that
"abc" because one is a list of characters (i.e.
[A?, B?, C?]) and one is a UTF8 binary (i.e.
<<65, 66, 67>>).
You can convert one into the other, though, if you are trying to work that way:
1 2 3 4 5
But the best thing to do is to think of them as two very separate things. If you’re working with Strings, you’re really working with UTF8 encoded binaries. If there are valid UTF8 codes contained inside the binary, you’ll get a string returned. If not, you’ll get a generic binary. Understanding this difference is crucial for working with Strings in Elixir, especially when coming from another language like Ruby.
Lastly, I learned how to find things in the documentation. Understanding how the standard library works is key to being effective in any language, and the available docs are okay. They’re not great though. Lots of holes and sometimes it’s difficult to understand exactly what an argument does.
This is the key part of Elixir and I have to admit that I know very little about it. I intend to explore it more as I go forward and hopefully write another post outlinging what I’ve learned.
Elixir is a neat langauge. I think it will do more to influence developers in other languages than it will become a production ready system, but either way, it has taught me a handful of ideas that make me consider what advantages functional programming has and how I can incorporate them into my day to day work. Looking foward to diving in more.