Caesar Shift in Haskell
First of all, it's great that you use type signatures. However, your using snake_case, whereas Haskell usually uses camelCase for functions, e.g. no_shift should be called noShift.

Next, your shift functions for characters can be simplified by both pattern matching and succ and pred:

shiftForwards :: Char -&gt; Char
shiftForwards 'z' = 'a'
shiftForwards c   = succ c

shiftBackwards :: Char -&gt; Char
shiftBackwards 'a' = 'z'
shiftBackwards c   = pred c


Next, your "global" function gets easier if you use str as an argument and not in a lambda.

shiftStr :: Int -&gt; [Char] -&gt; [Char]
shiftStr num str
       | num &gt; 0  = shiftStr (num - 1) (map shiftForwards str)
       | num &lt; 0  = shiftStr (num + 1) (map shiftBackwards str)
       | num == 0 = str


The special cases for num == 1 and num == -1 aren't necessary, since shiftStr will return immediately if the subsequent call uses num = 0.