Skip to content

Puzzles

A collection of CLEAN code snippets for common questions and problems.

Break an integer into its digits

Problem

Given an integer \(n\), how can we obtain each individual digit of it?

Expected result

// CLEAN

toDigits 123   // [1, 2, 3]
toDigits 456   // [4, 5, 6]
toDigits 1234  // [1, 2, 3, 4]
toDigits 4567  // [4, 5, 6, 7]

Using recursion

Solution

// CLEAN

toDigits :: Int -> [Int]
toDigits    n 
| (abs n) < 10  =  [n]
| otherwise     =  (toDigits (n / 10)) ++ [n rem 10]

Explanation:

This approach takes advantage of the reminder division operation. Before the next iteration, \(n\) is divided by \(10\), this step removes the last digit of \(n\) since it has already been placed in the list.

The abs expands domain of our function from \([0,\ \infty)\) to \((-\infty,\ \infty)\).

List comprehension

// CLEAN

toDigits :: Int -> [Int]
toDigits    n   =  [(toInt d) - 48 \\ d <-: (toString n)]

Explanation

Since arrays can be freely converted to lists and vice versa, we can convert \(n\) to an array.

In this case, \(n\) is converted into an array of \(\text{Char}\). \(\text{toInt}\) then converts each digit of \(n\) to \(\text{Int}\).

However, the \(\text{Char}\rightarrow\text{Int}\) conversions are ASCII based. That is - character \(1\) converts to integer value \(49\), - character \(2\) converts to integer value \(50\), and so on.

In the final step, an offset value of \(48\) is subtracted from the result.


Computing divisors of an integer

Expected result

// CLEAN

divisorsOf 9  // [1, 3, 9]
divisorsOf 16 // [1, 2, 4, 8, 16]
divisorsOf 2  // [1, 2]
divisorsOf 0  // [0]

List comprehension

// CLEAN

isDivisible :: Int Int -> Bool
isDivisible    x   y   =  (x rem y) == 0

divisorsOf :: Int -> [Int]
divisorsOf    0   =  [0]
divisorsOf    n   =  [d \\ d <- [1..(abs n)] | isDivisible n d]

Explanation:

A list of integers is generated. It contains integers in \([1,\ \lvert{n}\rvert]\) interval.

The helper function \(\text{isDivisible}\) determines which integer will be placed in the list, and which integer will be discarded.

If an integer \(d\) is a divisor of \(n\), it is included in the list. If it does not full divide \(n\), it is discarded.


Checking if an integer is prime

Expected result:

// CLEAN

isPrime 9 // False
isPrime 3 // True
isPrime 1 // False
isPrime 0 // False

Counting divisors list (comprehension)

// CLEAN

isPrime :: Int -> Bool
isPrime 0 = False
isPrime 1 = False
isPrime n = length (filter isDivisorOfN [d \\ d <- ds]) == 0
where
    ds :: [Int]
    ds =  [2..(n - 1)]

    isDivisorOfN :: Int -> Bool
    isDivisorOfN k = (n rem k) == 0

Explanation:

For \(n \gt 1\), a list of integers from \(2\) to \(n - 1\) is constructed. The list filtered to only contain divisors of \(n\).

If the divisor list is empty, \(n\) is a prime number.

Using list of booleans

// CLEAN

isPrime :: Int -> Bool
isPrime 0 = False
isPrime 1 = False
isPrime n = not (or [n rem d == 0 \\ d <- [2..(n - 1)]])