import Data.List(elemIndex) data Result = Valid | BadCheck | TooLong | TooShort | InvalidContent deriving Show -- convert a list of Maybe to a Maybe list. -- result is Nothing if any of values from the original list are Nothing allMaybe :: [Maybe a] -> Maybe [a] allMaybe = sequence toValue :: Char -> Maybe Int toValue c = elemIndex c $ ['0'..'9'] ++ ['A'..'Z'] ++ "*@#" -- check a list of ints to see if they represent a valid CUSIP valid :: [Int] -> Bool valid ns0 = let -- multiply values with even index by 2 ns1 = zipWith (\i n -> (if odd i then n else 2*n)) [1..] $ take 8 ns0 -- apply div/mod formula from site and sum up results sm = sum $ fmap (\s -> ( s `div` 10 ) + s `mod` 10) ns1 in -- apply mod/mod formula from site and compare to last value in list ns0!!8 == (10 - (sm `mod` 10)) `mod` 10 -- check a String to see if it represents a valid CUSIP checkCUSIP :: String -> Result checkCUSIP cs | l < 9 = TooShort | l > 9 = TooLong | otherwise = case allMaybe (fmap toValue cs) of Nothing -> InvalidContent Just ns -> if valid ns then Valid else BadCheck where l = length cs testData = [ "037833100" , "17275R102" , "38259P508" , "594918104" , "68389X106" , "68389X105" ] main = mapM_ putStrLn (fmap (\s -> s ++ ": " ++ show (checkCUSIP s)) testData)