Honestly, this is a case that I'd just solve with a compositional breakdown.
data Tree a = Empty | Node a (Tree a) (Tree a) deriving (Show)
toMap :: Ord a => Tree a -> [(a, Int)]
toMap = countDups . toList
Note that I had to add an extra constraint on a
. It needs at least Eq
to be solvable at all, but Ord
allows asymptotically better solutions.
The basic idea here is just breaking the solution down into parts, and figuring out each part later. So, the next part is toList
. I'm not going to assume the order matters, and as such I'll choose a prefix ordering, since it's easy to make both lazy and simple.
toList :: Tree a -> [a]
toList Empty = []
toList (Node a l r) = a : toList l ++ toList r
Ok, nice and straightforward. On to counting the duplicates. Let's break this down into a few pieces, too.
countDups :: Ord a => [a] -> [(a, Int)]
countDups = map (\xs -> (head xs, length xs)) . group . sort
Ok, I may have slightly cheated there by taking advantage of group
and sort
from Data.List
. But on the other hand, this is exactly the kind of problem group
is meant to solve. And sorting is just a standard tool for everything.
If I had Control.Arrow
imported, I'd replace the lambda with (head &&& length)
. But that's just a bit of a standard idiom that doesn't really simplify things - it just makes them a bit more succinct to type.
The main idea of this approach is breaking down the problem into pieces that do some meaningful thing on their own. Then compose those pieces together into a full solution. It's handy to have a way to convert a Tree a
into a [a]
. Might as well have a function that does that. And once you do, the remaining piece is a useful bit of logic to have available for processing lists. And if you break that down, you find it's an easy composition of existing bits list functionality.
This is often one of the best ways to solve problems in any programming language - break the big task down into smaller tasks. What's nice about doing it in Haskell is that composing the smaller tasks into the full process is a nicely succinct process.