Let's start by just making the definition
foo [('a',2), ('b', 6), ('c', 1)] = "aabbbbbbc"
Is this a correct definition? Yes.
Is there some problem with it? Yes, it is not general enough. It will only accept a very very specific and narrow form of input, and error out on everything else:
> foo [('a',2), ('b', 6), ('c', 1)]
"aabbbbbbc"
it :: [Char]
> foo [('a',2), ('b', 6), ('c', 2)]
"*** Exception: <interactive>:13:5-51: Non-exhaustive patterns in function foo
Anything else wrong with that definition? Well, not wrong per se, but it's lacking a type signature. GHCi can infer the type for us:
> :t foo
foo :: (Num t, Eq t) => [(Char, t)] -> [Char]
but it seems too general for comfort. We can specialize is e.g. as
foo :: [(Char, Int)] -> [Char]
So, with this type, what can be done about the definition? Starting from the missing case, we add
foo [('a',2), ('b', 6), ('c', 2)] = "aabbbbbbcc"
foo [('a',2), ('b', 6), ('c', 3)] = "aabbbbbbccc"
All correct cases. But what about making them more general?
For that, we try re-writing it and trying to see some patterns in it:
foo [('a',2), ('b', 6), ('c', 4)] = "aabbbbbbcccc"
= "aabbbbbb" ++ "cccc"
= "aabbbbbb" ++ replicate _ 'c'
What is the value to go into that _ slot?
When you've answered that, you'll be able to also complete this one:
foo [('a',2), ('b', 6), ('c', n)] = "aabbbbbbcccc"
= "aabbbbbb" ++ "cccc"
= "aabbbbbb" ++ replicate _ 'c'
and this one:
foo [('a',2), ('b', m), ('c', n)] = "aabbbbbbcccc"
= "aabbbbbb" ++ "cccc"
= "aa" ++ replicate _ _ ++ replicate _ 'c'
and isn't this the same as
foo ( ('a',2) : [('b', m), ('c', n)] ) =
= replicate _ 'a' ++ foo [('b', m), ('c', n)]
or even
foo ( h : t )
| h == ('a',2)
, t == [('b', m), ('c', n)] )
= replicate _ (fst h) ++ foo t
… right?
Could you continue this line of thought to its conclusion? Do you see how the code practically writes itself when we generalize our concrete cases by replacing concrete terms with variables?