I would not worry about global variables. Assuming that this code will be properly placed inside its own module, those would probably not be global anyway.
Use of parentheses
Some parentheses are superfluous. For example, the whole body of the second
rotStr equation is enclosed in parentheses and those can be removed.
Regarding the other cases, you can probably avoid parens (and get slightly easier to digest code) if you define subexpressions in a
I'm not sure what you mean by that. If you mean the
getArgs part, that looks OK.
Here are some other notes about the code:
rotStr 0 s = s line is superfluous. You can remove it and everything will work just fine. I assume it is just an optimization, so that's OK.
- It might not be obvious for small inputs, but the performance of the code can be improved. Things like
elemIndex c alnum and
alnum !! run in linear time in the size of
alnum. This means that the expression
elem c alnum = alnum !! (mod (r + fromJust (elemIndex c alnum)) anlen) will go through the list 2 times. Again, this might not matter much, but you could use
Data.Maps for lookup in order to get better performance.
Here's a possible implementation using
import qualified Data.Map as M (Map, empty, insert, lookup)
alnum = ['A' .. 'Z'] ++ ['a' .. 'z'] ++ ['0' .. '9']
anlen = length alnum
indices = foldr add M.empty $ zip alnum [0..]
where add (c, i) m = M.insert c i m
charsByIndex = foldr add M.empty $ zip alnum [0..]
where add (c, i) m = M.insert i c m
rotChar :: Int -> Char -> Char
rotChar r c = case M.lookup c indices of
Just i -> fromJust $ M.lookup (newIndex i) charsByIndex
Nothing -> c
where newIndex i = (i+r) `mod` anlen
rotStr :: Int -> String -> String
rotStr r s = map (rotChar r) s
Also note that the last line can be reduced to:
rotStr = map . rotChar