How to get strings 'aa', ab' up to 'yz', 'zz'?

Viewed 140

How to get strings from 'aa' up to 'zz' in a list? I know it is obvious, but don't know the proper idiom to solve that kind of problems. Just show the idea with concrete examples and I'll figure out the rest. Thanks.

Tried

(++) <$> ['a'..'z'] <*> ['a'..'z']

but it doesn't compile.

1 Answers

All of these do what you want (remember String = [Char]):

Control.Monad.replicateM 2 ['a'..'z'] -- Cleanest; generalizes to all Applicatives
sequence $ replicate 2 ['a'..'z'] -- replicateM n = sequenceA . replicate n
-- sequence = sequenceA for monads
-- sequence means cartesian product for the [] monad

[[x, y] | x <- ['a'..'z'], y <- ['a'..'z']] -- Easiest for beginners
do x <- ['a'..'z']
   y <- ['a'..'z']
   return [x, y] -- For when you forget list comprehensions exist/need another monad
['a'..'z'] >>= \x -> ['a'..'z'] >>= \y -> return [x, y] -- Desugaring of do
-- Also, return x = [x] in this case
concatMap (\x -> map (\y -> [x, y]) ['a'..'z']) ['a'..'z'] -- Desugaring of comprehension
-- List comprehensions have similar syntax to do-notation and mean about the same,
-- but they desugar differently

(\x y -> [x, y]) <$> ['a'..'z'] <*> ['a'..'z'] -- When you're being too clever
(. return) . (:) <$> ['a'..'z'] <*> ['a'..'z'] -- Same as ^ but pointfree

The reason

(++) <$> ['a'..'z'] <*> ['a'..'z']

doesn't work is because you need (++) :: Char -> Char -> [Char], but you only have (++) :: [Char] -> [Char] -> [Char]. You can throw in returnss on top of the arguments to (++) to put the Chars into singleton lists and get things to work:

(. return) . (++) . return <$> ['a'..'z'] <*> ['a'..'z']
Related