Is dense good?
I cannot decide what I feel about the differences between my JavaScript and Haskell solution of the Vigenère cipher.
In natural languages, we speak about information density, and as far as I know, information density evens out if we provide time as a parameter. That is, a dense language is spoken and understood more slowly than a 'chatty' counterpart.
How should we think about terse programming languages? What do dense expressions lead to? Something elegant usually takes more time to articulate, but usually also more time to understand. Given a context that does not favor quick-fix solutions, this is most likely something good (especially in the long run) but what about environments that want results fast?
function vigenere(key) {
const AZ_LENGTH = 26;
const alphabetAZ = Array
.from(
{length: AZ_LENGTH},
(_, i) => String.fromCharCode(i + 65)
);
const table = alphabetAZ.reduce((table, v, i) => ({...table, [v]: i}), {});
const cryptoStr = (msg, key) => ''.padStart(msg.length, key);
const cryptoStrLetterAt = (msg, key, pos) => cryptoStr(msg,key)[pos];
return {
encrypt: (msg) => msg
.split('')
.map(
(char, i) => alphabetAZ[
(table[char] + table[cryptoStrLetterAt(msg, key, i)]) % AZ_LENGTH]
)
.join(''),
decrypt: (msg) => msg
.split('')
.map(
(char, i) => alphabetAZ[
(table[char] - table[cryptoStrLetterAt(msg, key, i)] + AZ_LENGTH) % AZ_LENGTH]
)
.join('')
}
}
// --------------------------------
const code = vigenere('LEMON');
console.log(code.encrypt('ATTACKATDAWN')); // LXFOPVEFRNHR
console.log(code.decrypt('LXFOPVEFRNHR')); // ATTACKATDAWN
import Data.Char
shift (senLetter, keyLetter) fn = chr $ start + (ord senLetter `fn` ord keyLetter) `mod` azLength
where
start = ord 'A'
azLength = 26
encode sentence key = map (`shift` (+)) $ zip sentence $ cycle key
decode sentence key = map (`shift` (-)) $ zip sentence $ cycle key
-- --------------------------------
encode "ATTACKATDAWN" "LEMON" -- LXFOPVEFRNHR
decode "LXFOPVEFRNHR" "LEMON" -- ATTACKATDAWN