Global "variables"
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 let
or where
clause.
Argument parsing
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:
- The
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.Map
s for lookup in order to get better performance.
Here's a possible implementation using Map
s:
import Data.List
import Data.Maybe
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