I am picking up good Haskell practices!
In this instance, I wanted to pick a file which contains a title in the first line and then every line is a string.
Each string represents a number in base equal to the number of distinct characters that appear on the string, but we do not know what characters correspond to each digit.
We want to find out the difference between the max and min number a string could represent, with the added restriction that a number cannot have leading 0s.
I feel like my code is quite complicated for such a simple task. Can I get any pointers on how to improve it so its more readable and elegant?
import qualified Data.Map as Map import Data.List import Data.Maybe main = do contents <- (tail . lines) <$> readFile "submitInput" :: IO [String] let input = contents :: [String] let result = max_range <$> input let decorated_result = ["Case #" ++ show i ++ ": " ++ show s | (i,s) <- zip [1..] result] writeFile "output.txt" $ unlines $ decorated_result -- Computes the difference between the max and min possible decoding max_range word = max_decoding word - min_decoding word -- Computes the minimal possible decoding of word min_decoding :: String -> Integer min_decoding word = let number = fix_decoding $ min_aux word (Map.empty :: Map.Map Char Integer) 0 in base_conversion (toInteger . length . nub $ number) $ catMaybes number -- The decodification cannot have leading zeros fix_decoding :: [Maybe Integer] -> [Maybe Integer] fix_decoding  =  fix_decoding (Just 0:ds) = Just 1 : fix_decoding ds fix_decoding (Just 1:ds) = Just 0 : fix_decoding ds fix_decoding (d:ds) = d : fix_decoding ds min_aux :: [Char] -> Map.Map Char Integer -> Integer -> [Maybe Integer] min_aux  _ _ =  min_aux (c:cs) map next | c `Map.member` map = Map.lookup c map : min_aux cs map next | otherwise = Just next : min_aux cs (Map.insert c next map) (next + 1) -- Computes the maximal possible decoding of word max_decoding :: String -> Integer max_decoding word = let number = max_aux word (Map.empty :: Map.Map Char Integer) ((toInteger . length . nub $ word)-1) in base_conversion (toInteger . length . nub $ number) $ catMaybes number max_aux :: [Char] -> Map.Map Char Integer -> Integer -> [Maybe Integer] max_aux  _ _ =  max_aux (c:cs) map next | c `Map.member` map = Map.lookup c map : max_aux cs map next | otherwise = Just next : max_aux cs (Map.insert c next map) (next - 1) -- Interprets a list of digits as a number in a given base base_conversion :: Integer -> [Integer] -> Integer base_conversion base  = 0 base_conversion base (d:ds) = d * base ^ (length ds) + base_conversion base ds