You’ve possibly heard of this language recently. Elixir has been gaining publicity as a new framework called Phoenix has been making exciting claims.
Phoenix is advertised as a “Productive, Reliable and Fast” web framework and is built with Elixir. Before getting too excited about Phoenix I wanted to dive into Elixir and see what this mysterious language has to offer.
First things first. These companies already use Elixir:
That peeked my interest!
What will I do with such a beautiful language
Today I want to show you some of the joys that Elixir provides through a small HackerRank problem.
We’ll cover, basic functions, iterating over collections, getting user input, pipes, pattern matching and guards.
Before we get started with the problem let’s install Elixir and make a project!
Elixir has excellent instructions on getting up and running here!
Check that you’ve installed elixir properly by typing
elixir -v into your terminal or command prompt:
Elixir comes with excellent tools.
iexin your terminal/command prompt but we’ll get to that later.
Let’s get to coding this problem!
If you’re looking for an IDE to do your Elixir coding in, I strongly recommend VSCode with the vscode-elixir plugin installed. It’s lightweight, responsive and has the goodies like syntax highlighting and autocompletion. Hint: View -> Integrated Terminal will open a terminal which you can then use Iex in.
Navigate to a directory where you’d like to place your project (which is the solution to this code problem). Once you’ve navigated to this folder in your terminal, make a new project with the command
mix new hackerrank_sol. Of course you can call the project whatever you wish.
This creates a new folder with your Elixir project. Let’s open this folder in our favourite code editor. Our code will live inside the following file:
lib/hackerrank_sol.ex. Check that everything works by running
There is some code already in your
We’re going to leave this and start coding below it in a new module called
Solution (you can have multiple modules in one file).
The question requires us to get user input. Specifically a list of numbers. Let’s open up Iex in our terminal and have a look for what we need.
iex into your terminal and you’ll be greeted by the friendly REPL (Read Evaluate Print Loop) for Elixir. Use
h() often to find information on functions because the documentation is great.
Because we want to get IO from the user we will look at the IO module. List of modules here: https://hexdocs.pm/elixir/Kernel.html
iex we can see what IO exports and also ask for help like so:
Here I’m using `exports` to find out what IO exports
Now I’m using `h(IO.gets)` to ask Elixir what the function gets does.
Holy moly, we get an example and other nice information! A quick note on the name
/2 just means that the function takes two arguments. Similarly
/1 means one argument and
/0 means zero arguments. The fancy name for this is the arity of the function. (Now you have another awesome party fact)
Let’s use this function in
iex just to get a taste of what it returns.
Ok! We should really actually try to solve the question now!
Note: You can print to the console using
This problem can be summarized as such:
An element x is said to be between a and b if:
We then want to know how many different values of x there are.
Let’s divide this problem into three pieces:
This is really clean in Elixir. We have
IO.gets/1 which gets a line of input from the standard input. We will be getting 3 lines of input in this problem, and each line is a list of integers. Let’s create a general
getLine/0 function that gets a line from stdin and returns a list of numbers.
Here’s a naive implementation that should be quite easy to follow. Feel free to use iex to go through the lines and see what each line is doing.
If you want to test this function, fire up iex in your terminal using this command:
iex -S mix. This command lets you access your mix project within iex. If you make changes to the code you can also use
recompile() to recompile your work so you can play with the freshest code.
To test this function in
iex we type
Before making this code more idiomatic, let’s have a look at some great things provided by elixir. We’ve got this
@doc tag above the function. This is called a module attribute and it tells Elixir that you’ve provided documentation to the
getLine/0 function. Type
h(Solution.getLine/0) and observer your own documentation displayed in all its glory! (Notice that documentation supports markdown!)
This is beautiful professional documentation.
We won’t dwell on this now, but you can write executable doctests in your documentation as well. Most of the time when you see examples in documentation they’re executable to make sure they’re valid. This allows for great separation of unit and integration testing.
Let’s quickly go through the funky looking line:
converted_to_int = Enum.map(split_line, fn el -> String.to_integer(el) end)
We are mapping over a list of strings, and converting each element into an integer. The following is happening:
["1", "10", "3"] -- _Enum.map_ --> [1, 10, 3]
Each element is being passed into the anonymous function as
el which is then converting that string into an integer.
The final line of a function is implicitly returned. I find this actually encourages clean coding as it’s very hard to write weird nested conditionals which return strangely.
Let’s clean this up so everyone is impressed using another awesome Elixir operator…
We’re going to trust that every string is a valid integer (but you shouldn’t in the real world).
There is a pattern that has emerged in our function. Each line is taking the output of the function above it and putting it in as its first argument. Elixir gives us this cool operator:
|> which pipes the output from the left to the right.
Notice we remove the first argument of each function because it’s being handled by the pipe operator.
That’s input done! Now let’s tackle making sure x is a factor of all the elements in b.
I’ll skip to the chase. We need to find out the greatest common divisor of the elements in the list b. Then if x divides into the lowest common divisor it satisfies the condition that it is a factor of all the elements of b.
Did you instantly scream EUCLID’S ALGORITHM? A quick google later for finding the greatest common divisor you stumble across this mathematical formula.
Straight from wikipedia
You also remember an imperative way of coding this algorithm (from python’s standard library):
def gcd(a, b): """Calculate the Greatest Common Divisor of a and b. Unless b==0, the result will have the same sign as b (so that when b is divided by it, the result comes out positive). """ while b: a, b = b, a%b return a
We’re going to do even better and write our own in Elixir that uses the mathematical definition, provides great error messages and is still fast.
Elixir supports pattern matching as well as checking conditions on inputs to a function. Here’s a simple example of pattern matching:
What we’re saying here is that if the argument is
0 we want to run the top version of the function. If the argument is not
0 we’ll return it in a string.
Wait!!! We don’t want that third behaviour!
This works but unfortunately the argument
x can be anything! Luckily we have guards which allow us to add constraints to the arguments.
We can improve this pattern matching example by adding
is_integer guard like so:
Look what happens when we try to pass something invalid:
Taking our new guard for a test run.
We get a very helpful message that specifically shows where our argument failed. We can see that a list of
[1,2,3] failed to be
0. It also failed to be an integer.
We’ve now got more than enough to write our
There are more guards than code! (Psst, there is a way in Elixir to create your own combination guards, but that’s out of scope for today)
This also follows the mathematical definition of greatest common divisor! There is of course a faster way using remainders which I leave as an exercise to you. ()
We need to find the greatest common divisor of a whole list though…. To find the gcd of a list of numbers, we just need to reduce the numbers against a current greatest common divisor which we update with each element. I’ll use a diagram!
We start with this list:
[8, 4, 16, 2]
Then we use
gcd on the first two numbers:
Reducing -- List left to reduce------------------------------------gcd(8, 4) -- [16, 2]= 4 -- [16, 2]gcd(4, 16) -- = 4 -- gcd(4, 2) -- = 2
There is a function for doing exactly this called
Enum.reduce/2. This list reducing function can also be called
gcd since it’s calculating the greatest common divisor.
The lowest common multiple is much simpler now that we have a
gcd function. In fact it’s the following formula:
lcm(a, b) = a × b / gcd(a, b)
Damn that’s a great formula. We can very easily code this up, including the reducing as demonstrated.
Now that we have a way to grab input, a way to find the greatest common divisor and a way to find the lowest common multiple we almost have a way to find the solution.
We’re going to find the solution in the most boring way ever. We’re going to “loop” over each integer from the lowest common multiple to the greatest common divisor checking that the number satisfies both conditions of the problem. We’ll then count the resulting x values that satisfy the tests.
In the function we’ll write, we’ll take in the highest value (or the gcd of list b). We’ll also take in the lowest value (or the lcm of list a).
We’re checking first that the gcd value from list b is indeed greater than the lcm value from list a (otherwise guards fail and we return 0).
lowest..highest is a range. The docs say this.
“Defines a range”
1..3 is basically
[1,2,3] in the way we’re using it above. The code basically creates a range of all the possible values of x between the lowest and highest number, and then filters based on the two conditions. The first filter checks that x is a multiple of the lcm of list a. The second filter checks that x is a factor of the gcf of list b. Then we count the results :)
We can now put our pieces together to get the input, and calculate the result:
Congratulations for reading this far! Hopefully I’ve shown you that Elixir is a pleasure to work in. The pattern matching and guard concepts allow you to enforce better preconditions regarding what your functions will take.
Pattern matching goes a lot farther than what’s shown here, and it really makes for readable, lovely code. .
I haven’t covered how awesome the testing is in this language, or the fact that Elixir 1.6 comes with a code formatter. I didn’t even mention tail recursion or the actor model or how easy concurrent programming can be in this language.
I hope you enjoyed this whirlwind tour, and please leave a comment if you use Elixir or have been intrigued by this post! I also love applause and really appreciate it if you enjoyed this post.