I implemented the Vigenere cipher in haskell as a part of exercises for Haskell programming from first principles.
Though the code isn't all that long, I feel it could use some refactoring to simplify things (I feel the code I wrote is ugly). One caveat: string inputs should all be in uppercase.
The vigenere
function should be applied like so:
vignere "ALLY" "MEET AT DAWN"
which will create the output:
"MPPRAEOYWY"
As it stands, here's the code I implemented:
import Data.Char
-- exercise chapter 11
encode :: Char -> Int
encode x = ord x - ord 'A'
decode :: Int -> Char
decode x = chr (x + ord 'A')
shift :: (Int -> Int -> Int) -> Int -> Char -> Char
shift f x ch = decode $ f (encode ch) x `mod` 26
rightShift :: Int -> Char -> Char
rightShift = shift (+)
leftShift :: Int -> Char -> Char
leftShift = shift (-)
encodeString :: String -> [Int]
encodeString str = map encode str
type Secret = String
type PlainText = String
type CipherText = String
vignereString :: Secret -> PlainText -> String
vignereString secret plain = take len $ cycle secret
where len = length $ concat $ words plain
vignereCode :: Secret -> PlainText -> [Int]
vignereCode secret plain = encodeString $ vignereString secret plain
vignere :: Secret -> PlainText -> CipherText
vignere secret plain =
zipWith rightShift code plainNoSpace
where code = vignereCode secret plain
plainNoSpace = concat $ words plain
unvignere :: Secret -> CipherText -> PlainText
unvignere secret cipher =
zipWith leftShift code cipherNoSpace
where code = vignereCode secret cipher
cipherNoSpace = concat $ words cipher