Vigenère cipher: Difference between revisions

→‎{{header|TXR}}: Extensions in TXR's lazy facilities make shorter work of this.
(Simpler D code)
(→‎{{header|TXR}}: Extensions in TXR's lazy facilities make shorter work of this.)
Line 1,887:
 
=={{header|TXR}}==
 
{{trans|Perl 6}}
 
Well, not exactly a translation but similar. The mapcar function vectorizes the operation over the characters, like Perl 6 hyper-operators. The repetition of the vigenere key is performed by a lazy list created by vig-pad. Perl 6 hyper-operators have this repetition behavior built-in, evidently.
 
<lang txr>@(next :args)
@(do
(defun letter-mod26-op (func) ;; add or subtract capital letters modulo 26
(defun str-to-list (str)
(for ((i 0) l) ((< i (length str)) (nreverse l)) ((inc i))
(push (chr-str str i) l)))
(defun vig-pad (key)
(let ((i 0) (m (length key)))
(make-lazy-cons (lambda (lcons)
(rplaca lcons (chr-str key i))
(rplacd lcons (make-lazy-cons (lcons-fun lcons)))
(set i (mod (+ i 1) m))))))
(defun chrmod (func)
(lambda (a b) (+ #\A (mod (call func (- a #\A) (- b #\A)) 26))))
(defun vig (msg key encrypt)
(letcat-str (mapcar (letter-mod26-op (if encrypt (fun +) (fun -))))
(cat-str (mapcar (chrmod op) (str-to-list msg) (viglist-padstr key)) "")))msg)
(rplaca lconsrepeat (chrlist-str key))) i"")))
@(coll)@{key /[A-Za-z]/}@(end)
@(coll)@{msg /[A-Za-z]/}@(end)
Line 1,925 ⟶ 1,913:
@(end)</lang>
 
Here, the TXR pattern language is used to scan letters out of two arguments, and convert them to upper case. The embedded TXR Lisp dialect handles the Vigenère logic, in just a few lines of code.
<pre>$ ./txr -l vigenere.txr 'vigenere cipher' 'Beware the Jabberwock... The jaws that... the claws that catch!'
 
The Vigenère substitution is driven by good old Lisp <code>mapcar</code> which works over the data represented as lists of characters (provided by applying the <code>list-str</code> function to the string inputs).
 
Now <code>mapcar</code> walks lists in parallel, stopping at the end of the shortest list. This traditional behavior of <code>mapcar</code> turns out to be a very good idea when you introduce infinite lazy lists into the mix. Infinite lists are longer than concrete lists and so mapcar keeps going until the shortest concrete list runs out.
 
We can represent the text to be enciphered or deciphered as a concrete list of the letters, and the Vigenère key as an infinite lazy list, giving us a key pad which consists of an infinite number of repetitions of the key. Such a list is produced by TXR Lisp's <code>repeat</code> operator, which takes a list and makes a lazy list out of repetitions of that list.
 
Then <code>mapcar</code> will zip the text and the infinite key pad two together, through the addition or subtraction operation.
 
TXR Lisp's <code>+</code> and <code>-</code> operators are generic over characters. An integer may be added to a character to produce a displacement through the code space to get to another character. When a character is subtracted from another, the result is an integer which is the difference between their codes.
 
<pre>$ ./txr -l vigenere.txr 'vigenere cipher' 'Beware the Jabberwock... The jaws that... the claws that catch!'
text: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH
key: VIGENERECIPHER
Anonymous user