Learning Elixir by Building a Happy Number Finder

Scott Luptowski
Made by Many
Published in
6 min readFeb 11, 2016

I recently started learning Elixir and decided to build a Happy Number Finder. This is one of my favorite programming problems — despite the name, it has very little to do with math. Instead, the solution to a Happy Number Finder involves recursion, type conversion, and list comprehension, all valuable things to know how to do when encountering a new language.

So what is a Happy Number?
Let’s ask Wikipedia: “Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number either equals 1 [a happy number], or it loops endlessly in a cycle which does not include 1 [an unhappy number]”

Let’s get started

We will demonstrate the process above with the happy number of 49. First, we must find a way to take the number 49 and turn it into the numbers 4 and 9. Then we need to square each of the numbers and add up the results. If the number is 1, the number is happy and we are done. If the number is not 1, we re-try with the new number and see if we end up with 1.

In many languages, including JavaScript and Ruby, getting from 49 to 4 and 9 would require you to turn the number into a string so you can split the string at every character and then turn each character back into an integer. Not Elixir — you can pass any number into the Integer.digits/2 function to receive a list of its digits.

Note: in Elixir, functions are referenced by their name and their expected number of arguments, ie. digits/2. In the case of this particular function, the second argument is optional.

Next, we must square each of the numbers and sum up the list. Let’s do this the long way first before we come up an Elixir-like solution.

We’ve ended up at 97, which is not 1. We know that we need to call get_sum/1 with 97. But before we introduce recursion into this program we should refactor a bit to get to a more idiomatic Elixir solution. We can use the |> pipe operator to pipe the results of the preceding function calls into the next calls.

We can clean this up a bit further and use Elixir’s & operator. This shortcut lets you turn an expression into a function by wrapping the call with & and naming your parameters &1, &2, etc: for instance, (&1 + 1) is the same as fn (x) -> x + 1 end

There’s a point where terseness impacts overall readability and I’d argue that the first pipe example is more clear about its intentions than this last one. Anyway, let’s carry on.

Now we have a function that determines if the given number is happy. Let’s set up the recursion.

We can see this code in action with the number 49, which is a happy number.

Great! But what happens when we pass in a number that is not happy?

Well, the terminal window freezes. You shouldn’t see anything on your terminal window, but Elixir is working hard — we’re recursing infinitely. It would be helpful here to know exactly what values Elixir is trying to compute. Let’s temporarily break an Elixir rule and introduce a side effect into our function, in this case using the IO.puts/1 function to log out some information to our console.

Before re-running the function with an unhappy number, add this line inside the body of find/1:

Do you see a pattern? At a certain point, numbers begin to repeat themselves, and the same pattern of numbers repeats infinitely. Put another way: as soon as we see a duplicate guess, we know the number is not happy, because we know that a duplicate guess means that the recursion will continue infinitely.

This is great! We know how to solve this. Right?

Immutability

This is the first time Elixir’s immutable data has mixed things up for us. Imagine how we would solve this in a language like JavaScript, which has mutable state. We would maintain an array (likely a global variable) of past guesses and append to this array every time we made a new guess. Then we would check if the current number was present in this array of guesses, and stop recursing if so.

But mutating is not possible in Elixir, so how do we solve this problem? We will need to pass in the list of past guesses into find/1 so that each time we run it, the function call has its own copy of the guesses up to that point.

Let’s change the body of find/1 to call a new function that we will name _find/2, and move all of our existing work into that new function. The first time we call _find/2 from inside find/1, we will pass in an empty list.

This lets us preserve the nice method signature of find/1 and hides the implementation of passing around a list of guesses. And how do we pass around that new list? Check out line 14 below, where we use [sum | guesses] to create a new list: the head of the list is our newest guess, and the tail is a list of past guesses.

Finally, we can make _find/2 a private function by defining it with defp instead of def; this reinforces the private nature of its contents and solidifies our public API around the find/1 function.

Now that find/1 and _find/2 are aware of the list of guesses, the next step is to determine whether or not the current number is in the list of past guesses and to stop recursing.

A Foray into Guard Clauses

Guard clauses are a neat Elixir feature that allows us to create multiple definitions of functions and rule that certain ones only execute under given conditions.

We know what our case is: if our number is part of the past list of guesses, we should stop the recursion. Note our guard clause on line 9 below.

Add this function definition to the module. Now there are two definitions of _find/2: one which executes if the number is in the guesses list, and one that runs other times. Clever, right? But what happens when we try to compile this code?

(ArgumentError) invalid args for operator “in”, it expects a compile time list or range on the right side when used in guard expressions, got: guesses

Elixir doesn’t like this. The compiler is helping us by telling us that to use a guard clause, we must provide a list or range populated with all of the values that should trigger this function definition instead of the other definition. This isn’t something that is known at compile time; it is only known at runtime. We’ve been too clever for our own good. Let’s delete this second function definition and concentrate on the body of the original function.

We can refactor _find/2 to use a case statement to determine if the number is in the past guesses list. I also took this opportunity to move some of the other logic into another helper function, compute_result/2, so that we are clear about our intentions inside _find/2.

Here is the final code:

Every time _find/2 is called, we check if the current number appears in the list of guesses. If it does not, we call compute_result/2, which sums up the squares of the number and determines if the number is happy or if we should call _find/2 again.

Let’s try with a happy number and an unhappy number and see the results.

And it works! Thanks for reading, and I hope you learned something about Elixir.

--

--