content: import Data.Char
  import Data.Map
  
  charToInt :: Char -> Int
  charToInt c = ord c - ord '0'
  
  -- Given a string, decode a single character from the string.
  -- Return the decoded char and the remaining undecoded string.
  decodeChar :: String -> (Char,String)
  decodeChar ('7':'9':r:rs) = (r,rs)
  decodeChar ('7':r:rs)     = ("PQUVWXYZ. " !! charToInt r, rs)
  decodeChar ('3':r:rs)     = ("ABCDFGIJKN" !! charToInt r, rs)
  decodeChar (r:rs)         = ("HOL MES RT" !! charToInt r, rs)
  
  -- Decode an entire string.
  decode :: String -> String
  decode [] = []
  decode st = let (c, s) = decodeChar st in c:decode s
  
  -- Given a string, decode a single character from the string.
  -- Return the decoded char and the part of the encoded string
  -- used to encode that character.
  revEnc :: String -> (Char, String)
  revEnc enc = let (dec, rm) = decodeChar enc in (dec, take (length enc - length rm) enc)
  
  ds :: String
  ds = ['0'..'9']
  
  -- Decode all 1000 possible encodings of three digits and
  -- use results to construct map used to encode.
  encodeMap :: Map Char String
  encodeMap = fromList [ revEnc [d2,d1,d0] | d2 <- ds, d1 <- ds, d0 <- ds ]
  
  -- Encode a single char using encoding map.
  encodeChar :: Char -> String
  encodeChar c = findWithDefault "" c encodeMap
  
  -- Encode an entire string.
  encode :: String -> String
  encode st = concatMap encodeChar $ fmap toUpper st
  
  -- Test by encoding, decoding, printing results.
  main = let orig = "One night-it was on the twentieth of March, 1888-I was returning"
             enc = encode orig
             dec = decode enc
         in mapM_ putStrLn [ "Original: " ++ orig
                           , "Encoded: " ++ enc
                           , "Decoded: " ++ dec ]
  