Collatz Conjecture

I find it interesting how how the language I write code in shapes the solution I gravitate towards. The other day I realized that I had solved the same problem Collatz Conjecture from exercism.io in three different languages.

From exercism the assignment text is as follows:

The Collatz Conjecture or 3x+1 problem can be summarized as follows: Take any positive integer n. If n is even, divide n by 2 to get n / 2. If n is odd, multiply n by 3 and add 1 to get 3n + 1. Repeat the process indefinitely. The conjecture states that no matter which number you start with, you will always reach 1 eventually. Given a number n, return the number of steps required to reach 1.

Haskell

In haskell guards | are readily available and it is very easy to create recursive functions using guards with base cases. My solution ended up like this:

collatz :: Integer -> Maybe Integer
collatz n | n <= 0    = Nothing
          | n == 1    = Just 0
          | even n    = fmap (+1) $ collatz $ div n 2
          | otherwise = fmap (+1) $ collatz $ n * 3 + 1

Clojure

With clojure having iterators in the root namespace they are always at the forefront of my mind when coding clojure. its easy to create a pattern with where we have an infinite sequence of next-collatz that we take form until we reach our predicate:

(defn next-collatz
  [n]
  (if (even? n)
    (/ n 2)
    (+ 1 (* 3 n))))

(defn collatz [n]
  (->> (iterate next-collatz n)
       (take-while #(not= % 1))

Scala

I write scala in my day job currently. Normally I would not think to use iterators for this so perhaps this is a bad example in the context of this post.

When writing this in Scala I was colored by remembering how I solved this in Clojure. I am however happy with how it ended up and I think I will try to reach for iterators more often in Scala also.

private def isEven(i: Int): Boolean = i % 2 == 0
private def nextCollatz(n: Int): Int =
  if (isEven(n)) n / 2
  else n * 3 + 1

// The solution in exercism requires that you use `Option`
def steps(n: Int): Option[Int] =
   Option(n)
     .filter(_ > 0)
     .map(Iterator.iterate(_)(nextCollatz).indexWhere(_ == 1))

Author | Thomas Bjertnes

Developer.