Reputation: 4089
I need to write "custom" ord and chr functions. I'm writing a little program to apply a Caesar cipher to a message. What is the fastest way to do this?
The function "ord" only needs to take a character and then return the appropriate number. 'A' should return 0, 'B' should return 1, etc. Assume that we're only going to use capital letters, so we only have 26 possibilities. I'd rather not write out 26 guards. Is there a better way to do this? Here's how they'll be used. The "chr" function should do the reverse.
caesarencipher::Int->Int->String->String
caesarencipher r s p = map chr . map encipher $ plaintext
where
plaintext = map ord p
encipher p = mod (r*p + s) 26
caesardecipher::Int->Int->String->String
caesardecipher r s c = map chr . map decipher $ ciphertext
where
ciphertext = map ord c
inverser x | mod (r * x) 26 == 1 = x
| otherwise = inverser (x + 1)
decipher c = mod ((inverser 1) * (c - s)) 26
Upvotes: 2
Views: 1078
Reputation: 12749
isAZ x = x >= 'A' && x <= 'Z'
ordAZ c | isAZ c = x where x = ord x - ord 'A'
chrAZ x | isAZ c = c where c = chr $ x + ord 'A'
Upvotes: 1
Reputation: 40797
If you really want the fastest way to define custom versions of these functions, then just write out every possible pattern. You can pack multiple clauses onto a line by separating them with semicolons.
However, I don't see what you'll gain. ord
and chr
aren't any slower just because they handle all codepoints; Char
already stores a complete Unicode codepoint. Indeed, ord
should be basically free, and chr
too (beyond the simple check for validity). So why not just apply the appropriate numeric offset to the standard ord
and chr
functions? (Note that even just writing out the patterns as I suggested above won't omit error-checking entirely; GHC will throw an exception if a value is passed that none of your clauses handle.)
Upvotes: 2