patternMinor
Vigenere cipher in Haskell
Viewed 0 times
vigenerehaskellcipher
Problem
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
which will create the output:
As it stands, here's the code I implemented:
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 cipherSolution
It's a nice solution, but very long for a relatively simple task.
First, note that the cipher is called "Vigenère", so
The type definitions…
… provide an illusion of type safety, where there actually isn't any. They are all just
All of the helper functions (
Hiding the
With the generalized
Here, I've written them using point-free style to emphasize the fact that
First, note that the cipher is called "Vigenère", so
vignere would be considered a misspelling.The type definitions…
type Secret = String
type PlainText = String
type CipherText = String… provide an illusion of type safety, where there actually isn't any. They are all just
Strings.All of the helper functions (
encode, decode, shift, rightShift, leftShift, and encodeString) could just be reduced to a single function:import Data.Char (chr, ord)
shift :: (Int -> Int -> Int) -> Char -> Char -> Char
shift op offset ch = numToChar $ (charToNum ch) `op` (charToNum offset)
where
charToNum ch = ord ch - ord 'A'
numToChar n = chr $ (n `mod` 26) + ord 'A'Hiding the
charToNum and numToChar helpers makes it easier to see what calls what.With the generalized
shift function defined, the enciphering and deciphering routines could each be one-liners:vigenere :: String -> String -> String
vigenere secret = zipWith (shift (+)) (cycle secret) . concat . words
unvigenere :: String -> String -> String
unvigenere secret = zipWith (shift (-)) (cycle secret) . concat . wordsHere, I've written them using point-free style to emphasize the fact that
vigenere secret acts as an enciphering filter on the text.Code Snippets
type Secret = String
type PlainText = String
type CipherText = Stringimport Data.Char (chr, ord)
shift :: (Int -> Int -> Int) -> Char -> Char -> Char
shift op offset ch = numToChar $ (charToNum ch) `op` (charToNum offset)
where
charToNum ch = ord ch - ord 'A'
numToChar n = chr $ (n `mod` 26) + ord 'A'vigenere :: String -> String -> String
vigenere secret = zipWith (shift (+)) (cycle secret) . concat . words
unvigenere :: String -> String -> String
unvigenere secret = zipWith (shift (-)) (cycle secret) . concat . wordsContext
StackExchange Code Review Q#148122, answer score: 6
Revisions (0)
No revisions yet.