Recently I've been trying out problems on codeforces to practice my algorithms and data structure problem solving skills.

This is a good chance to revise a language I know but haven't used for a while, or to pick up a new language. For me it was a chance to write some Haskell.

The particular problem I was working on is 1B. Take a minute to read it, it's an interesting problem.

In summary, there are 2 numeration systems, and if we are given system A, we need to translate it to system B, and vice versa.

I chose to write a function that decides if a given string belongs to system A. The function signature is simple.

isA :: String -> Bool

In short, system A is where you have:

  1. the letter 'R',
  2. followed by the row number,
  3. the letter 'C',
  4. finally the column number.

For example, these strings belong to system A:


My implementation looks something like this:

isA :: String -> Bool
isA ('R':ss) = hasNumbersThenC
    where hasNumbersThenC = nums /= []
         (nums, row) = splitAt posnC ss
         posnC = case elemIndex 'C' ss of
           Just n -> n
           Nothing -> 0
isA _ = False

So this isn't really idiomatic Haskell (I'm still learning), but the general idea is this:

  1. Use pattern matching to catch the first 'R'.
  2. Try to find a 'C' in the rest of the string (ss in the code)
  3. Split the remaining string (without 'R') by the position of 'C' So splitAt will return a tuple, with the first element having a length of posnC.
  4. Check that nums is not an empty list []. This check takes care that there is a 'C' in the string, and that there are letters before the 'C'.

This sounds like a pretty involved process and the code I wrote still feels imperative even though I'm using a functional language, so I thought a little bit about how to make it better.

And then it hit me, if I can pattern match on the 'R', can I pattern match on the 'C' as well?

isA :: String -> Bool
isA ('R':rs:'C':cs) = True
isA _ = False

And that's it!