HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Caesar Shift in Haskell

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
shiftcaesarhaskell

Problem

I started learning Haskell a couple of days ago and decided to build a Caesar shift in it.

import Data.Char

shift_str :: Int -> ([Char] -> [Char])
shift_str num
         | num > 1 = \str -> shift_str_forwards (shift_str (num-1) str)
         | num == 1 = shift_str_forwards
         | num == 0 = no_shift
         | num == -1 = shift_str_backwards
         | num  shift_str_backwards (shift_str (num+1) str)

no_shift :: [Char] -> [Char]
no_shift str = str

shift_str_forwards :: [Char] -> [Char]
shift_str_forwards str = map shift_forwards str

shift_str_backwards :: [Char] -> [Char]
shift_str_backwards str = map shift_backwards str

shift_forwards :: Char -> Char
shift_forwards char
             | char == 'z' = 'a'
             | otherwise = chr (1 + ord char)

shift_backwards :: Char -> Char
shift_backwards char
              | char == 'a' = 'z'
              | otherwise = chr (ord char - 1)


However, this seems far too complex to be the right way of doing it. Any advice?

Solution

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 -> Char
shiftForwards 'z' = 'a'
shiftForwards c   = succ c

shiftBackwards :: Char -> 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 -> [Char] -> [Char]
shiftStr num str
       | num > 0  = shiftStr (num - 1) (map shiftForwards str)
       | num < 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.

Code Snippets

shiftForwards :: Char -> Char
shiftForwards 'z' = 'a'
shiftForwards c   = succ c

shiftBackwards :: Char -> Char
shiftBackwards 'a' = 'z'
shiftBackwards c   = pred c
shiftStr :: Int -> [Char] -> [Char]
shiftStr num str
       | num > 0  = shiftStr (num - 1) (map shiftForwards str)
       | num < 0  = shiftStr (num + 1) (map shiftBackwards str)
       | num == 0 = str

Context

StackExchange Code Review Q#148307, answer score: 6

Revisions (0)

No revisions yet.