https://wiki.haskell.org/index.php?title=Haskell_Quiz/Count_and_Say/Solution_Dolio&feed=atom&action=history
Haskell Quiz/Count and Say/Solution Dolio - Revision history
2015-07-06T18:06:58Z
Revision history for this page on the wiki
MediaWiki 1.19.14+dfsg-1
https://wiki.haskell.org/index.php?title=Haskell_Quiz/Count_and_Say/Solution_Dolio&diff=15595&oldid=prev
Dolio: new page
2007-09-14T20:45:35Z
<p>new page</p>
<p><b>New page</b></p><div>[[Category:Haskell Quiz solutions|Count and Say]]<br />
<br />
While reading the description for this quiz, I thought it was a perfect problem to make use of the handy clusterBy function Tom Moertel recently [http://blog.moertel.com/articles/2007/09/01/clusterby-a-handy-little-function-for-the-toolbox discussed on his blog]. So, I whipped up this solution to see how it'd work.<br />
<br />
<haskell><br />
module Main (main, say, search) where<br />
<br />
import Data.Char<br />
import Data.List<br />
import Data.Maybe<br />
import qualified Data.Map as M<br />
<br />
import Control.Arrow<br />
import Control.Monad<br />
import System.Environment<br />
<br />
clusterBy :: Ord b => (a -> b) -> [a] -> [[a]]<br />
clusterBy p = M.elems . M.map reverse . M.fromListWith (++) . map (p &&& return)<br />
<br />
cluster :: Ord a => [a] -> [[a]]<br />
cluster = clusterBy id<br />
<br />
speak :: Int -> String<br />
speak 1 = "ONE"<br />
speak 2 = "TWO"<br />
speak 3 = "THREE"<br />
speak 4 = "FOUR"<br />
speak 5 = "FIVE"<br />
speak 6 = "SIX"<br />
speak 7 = "SEVEN"<br />
speak 8 = "EIGHT"<br />
speak 9 = "NINE"<br />
speak 10 = "TEN"<br />
speak 11 = "ELEVEN"<br />
speak 12 = "TWELVE"<br />
speak 13 = "THIRTEEN"<br />
speak 15 = "FIFTEEN"<br />
speak 18 = "EIGHTEEN"<br />
speak 20 = "TWENTY"<br />
speak 30 = "THIRTY"<br />
speak 40 = "FORTY"<br />
speak 50 = "FIFTY"<br />
speak 60 = "SIXTY"<br />
speak 70 = "SEVENTY"<br />
speak 80 = "EIGHTY"<br />
speak 90 = "NINETY"<br />
speak n | n < 20 = speak (n - 10) ++ "TEEN"<br />
| n < 100 = speak (n - m) ++ speak m<br />
| otherwise = error "Unanticipated number."<br />
where m = n `mod` 10<br />
<br />
say :: String -> String<br />
say = intercalate " " . map (\c -> speak (length c) ++ " " ++ take 1 c)<br />
. cluster . filter isAlpha<br />
<br />
search :: String -> Int<br />
search = (1+) . fromJust . search' []<br />
where search' l s = elemIndex s l `mplus` search' (s:l) (say s)<br />
<br />
main = print . search . map toUpper . head =<< getArgs<br />
</haskell></div>
Dolio