Vigenere cipher exercise in Haskell
To get rid of !! here, you can use it earlier and earlier until you never even generate an Int.

-- | Given 'key' &amp; 'msg' generate a list of [Maybe Int] indices
-- to map 'msg' from 'key', skipping invalid characters
toIdx :: Key -&gt; Msg -&gt; [Maybe Char]
toIdx k m = toIdx_ (cycle $ map toUpper k) m
  where toIdx_ :: Key -&gt; Msg -&gt; [Maybe Char]
        toIdx_ _ "" = []
        toIdx_ key@(k:ey) (c:cs)
          | isValid c = Just k : toIdx_ ey cs
          | otherwise = Nothing : toIdx_ key cs


-- | Given 'key' &amp; 'msg' generate a list of numbers representing
-- the amount to shift 'msg' characters based on 'key'
toShifts :: Key -&gt; Msg -&gt; [Int]
toShifts k m = map toKey (toIdx k m)
  where toKey :: Maybe Char -&gt; Int
        toKey Nothing  = 0
        toKey (Just x) = ord x - ord 'A'


Of course, there is hardly a need to separate all these steps.

base :: Char -&gt; Maybe Char
base c
  | 'a' &lt;= c &amp;&amp; c &lt;= 'z' = Just 'a'
  | 'A' &lt;= c &amp;&amp; c &lt;= 'Z' = Just 'A'
  | otherwise = Nothing

vigenere, unVigenere :: String -&gt; String -&gt; String
[vigenere, unVigenere] = (`map` [(+), (-)]) $ \direction k -&gt;
  (.) snd $ (`mapAccumL` cycle k) $ \key@(k:ey) c -&gt; case base c of
    Nothing -&gt; (key, c)
    Just a -&gt; (,) ey $ chr $ ord a +
      mod ((ord c - ord a) `direction` (ord (toUpper k) - ord 'A')) (ord 'Z' - ord 'A')