Number base manipulation in Haskell
Type signatures and naming

While it's good practice to use type signatures on top-level bindings, it's usually not necessary in expressions unless type classes are involved. For example, the two following lines don't need type signatures:

contents &lt;- (tail . lines) &lt;$&gt; readFile "submitInput" :: IO [String]
let input = contents :: [String]


readFile always returns IO String, and tail . lines always changes a String into a [String]. Furthermore, input = contents is a nop, so it's not clear why it's there.

Next, you usually use camelCase instead of snake_case in names in Haskell and hide the functionality in local bindings if you don't want to reuse functions, e.g.

min_decoding :: String -&gt; Integer
min_decoding word = 
    base_conversion (toInteger . length . nub $ number) $ catMaybes number
  where
    number = fix_decoding $ min_aux word Map.empty 0  
    min_aux = ...


Feel free to use let … in … instead. By the way, max_range is missing a type signature.

Recursion and Horner's method

Your base_conversion isn't really optimal. We can use Horner's method to get rid of length. For this we need a helper:

baseConversion :: Num a =&gt; a -&gt; [a] -&gt; a
baseConversion base = go 0
  where
    go acc []     = acc
    go acc (d:ds) = go (acc * base + d) ds


You can verify that this yields the same result:

baseConversion 10 [1,2,3,4,5]
   = go 0 [1,2,3,4,5]
   = go (0  * 10 + 1) [2,3,4,5]
   = go (1  * 10 + 2) [3,4,5]
   = go (12 * 10 + 3) [4,5]
   = go (123 * 10 + 4) [5]
   = go (1234 * 10 + 5) = 12345


But there's already a function for this, foldl':

baseConversion :: Num a =&gt; a -&gt; [a] -&gt; a 
baseConversion base = foldl' (\acc x -&gt; acc * base + x) 0


Either way, we got rid of the ^ (length ds) part.

Don't repeat yourself

Both min_decoding and max_decoding look very similar, and so do max_aux and min_aux.

We're repeating a lot of logic here. So instead, let us use a single function:

toDigit :: (Integer -&gt; Integer) -&gt; [Char] -&gt; Map.Map Char Integer -&gt; Integer -&gt; [Maybe Integer]
toDigit _    []     _   _    = []
toDigit step (c:cs) m next =
  | c `Map.member` m    = Map.lookup c m : toDigit cs m next
  | otherwise           = Just next : toDigit cs (Map.insert c next m) (step next)


Now

min_aux = toDigit (+1)
max_aux = toDigit (subtract 1)


Use appropriate types

But toDigit is still not optimal. We never return Nothing in our list. Therefore, there is no reason to use [Maybe Integer] as a result type:

toDigit :: (Integer -&gt; Integer) -&gt; [Char] -&gt; Map.Map Char Integer -&gt; Integer -&gt; [Integer]
toDigit _    []     _   _    = []
toDigit step (c:cs) m next = case Map.lookup c m of
  Just digit -&gt; digit : toDigit step cs map next
  Nothing    -&gt; next  : toDigit step cs (Map.insert c next m) (step next)


While we're at it, you probably want to replace Integer with Int for the digits.