content: import Data.Char (toUpper)
  import Data.Maybe (fromJust)
  
  validateIBAN :: String -> Either String String
  validateIBAN [] = Left "No IBAN number."
  validateIBAN xs =
      case lookupCountry of
          Nothing -> invalidBecause "Country does not exist."
          Just l  -> if length normalized /= l
                          then invalidBecause "Number length does not match."
                          else check
      where
          -- remove blanks and make all letters uppercase
          normalized = map toUpper $ concat $ words xs
          -- get the country code
          country = take 2 normalized
          -- search number length
          lookupCountry = lookup country countries
          countries :: [(String, Int)]
          countries = zip (words "AL AT BE BA BG HR CZ DO FO FR DE GR GT \
              \IS IL KZ LV LI LU MT MU MD NL PK PL RO SA SK ES CH TR GB \
              \AD AZ BH BR CR CY DK EE FI GE GI GL HU IE IT KW LB LT MK \
              \MR MC ME NO PS PT SM RS SI SE TN AE VG")
              [28,20,16,20,22,21,24,28,18,27,22,27,28,26,23,20,21,21,20,
              31,30,24,18,24,28,24,24,24,24,21,26,22,24,28,22,29,21,28,18,
              20,18,22,23,18,28,22,27,30,28,20,19,27,27,22,15,29,25,27,22,
              19,24,24,23,24]
          digits = ['0'..'9']
          letters = ['A'..'Z']
          -- letters to be replaced
          replDigits = zip letters $ map show [10..35]
          -- digits and letters allowed in the IBAN number
          validDigits = digits ++ letters
          -- see if all digits and letters in the IBAN number are allowed
          sane = all (`elem` validDigits) normalized
          -- take the first 4 digits from the number and put them at its end
          (p1, p2) = splitAt 4 normalized
          p3 = p2 ++ p1
          -- convert the letters to numbers and
          -- convert the result to an integer
          p4 :: Integer
          p4 = read $ concat $ map convertLetter p3
          convertLetter x | x `elem` digits = [x]
                          | otherwise       = fromJust $ lookup x replDigits
          -- see if the number is valid
          check = if sane
                      then if p4 `mod` 97 == 1
                              then Right xs
                              else invalidBecause "Validation failed."
                      else invalidBecause "Number contains illegal digits."
  
          invalidBecause reason = Left $ "Invalid IBAN number " ++ xs ++
              ": " ++ reason
  