# read re-implemented for Int's

I have written a safe read function for haskell (for education!). I think this is fairly idiomatic haskell code, but I'd like to know for sure. If you see anything else that could be improved, please let me know in your answer.

module ReadNum (readNum) where

main = print $readNum "87k7" readNum :: String -> Maybe Int readNum xs = readNum'$ reverse xs

readNum' :: String -> Maybe Int
readNum' (x:xs) = (\y z -> y + 10 * z) <$> readChr x <*> readNum' xs readNum' [] = Just 0 chrToNum :: [(Char, Int)] chrToNum = [('0', 0), ('1', 1), ('2', 2), ('3', 3), ('4', 4), ('5', 5), ('6', 6), ('7', 7), ('8', 8), ('9', 9)] readChr :: Char -> Maybe Int readChr c = lookup c chrToNum  ## 1 Answer The change I'd make, respecting your overall design, is to refactor chrToNum as this: chrToNum :: [(Char, Int)] chrToNum = zip "0123456789" [0..]  Apart from that, if we are willing to slightly alter the design, I would separate the string validation from the computation of the Int represented. The string validation can be done using mapM :: (a -> m b) -> [a] -> m [b] (this way we avoid explicitly writing the recursion). validateString :: String -> Maybe [Int] validateString = mapM readChr  Then, you can define a function computing the Int represented by a list of digits (I use foldl' which requires you to add import Data.List but you can equally well use reverse + foldr as you originally did) represents :: [Int] -> Int represents = foldl' (\ ih z -> 10 * ih + z) 0  Finally, putting it all together we get: readNum :: String -> Maybe Int readNum = fmap represents . validateString  • Cool, nice answer! So, mapM fails if any of the computations fail? (for the Maybe monad at least) Commented Mar 27, 2016 at 1:33 • Yes. mapM has a structure similar to the one of your readNum': mapM f [] = pure [] and mapM f (x : xs) = (:) <$> f x <*> mapM f xs. Commented Mar 27, 2016 at 12:34
• As a minor improvement: [0..] -> [0..9] to be more explicit. Commented Mar 27, 2016 at 18:58