Haskell’s powerful pattern matching
2015-09-11 14:05
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.
In short, system A is where you have:
- the letter ‘R’,
- followed by the row number,
- the letter ‘C’,
- finally the column number.
For example, these strings belong to system A:
R23C55
R4C8
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:
- Use pattern matching to catch the first ‘R’.
- Try to find a ‘C’ in the rest of the string (
ss
in the code) - 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
. - 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?
And that’s it!