Fun with simple lookup tables (and LOOP)

Table of Contents

Luhn Algorithm

In the book "Think Like a Programmer", one of the leading chapters discusses writing a Luhn Algorithm application. Once you read this correctly – so, two tries by me, due to late night reading – the code is straight forward and fun to consider.

The method taken by that text covers a very literal "by the algorithm" interpretation. There is absolutely nothing wrong with this, and it has several points in its favor. However, I have grown more interested in lookup table based approaches.

To that end, I thought I would try this with elisp. This further let me have fun with the LOOP macro. What I came up with is the following:

(defun luhn-check (code)
  (let ((len (length code)))
    (equal 0
           (mod (loop for i from 1 to len
                      sum (cadr (assoc (elt code (- len i))
                                       (if (equal (mod i 2) 0)
                                           '((?0 0)
                                             (?1 2)
                                             (?2 4)
                                             (?3 6)
                                             (?4 8)
                                             (?5 1)
                                             (?6 3)
                                             (?7 5)
                                             (?8 7)
                                             (?9 9))
                                         '((?0 0)
                                           (?1 1)
                                           (?2 2)
                                           (?3 3)
                                           (?4 4)
                                           (?5 5)
                                           (?6 6)
                                           (?7 7)
                                           (?8 8)
                                           (?9 9))))))
                10))))

(append '(("*Input*" "*Result*"))
        (mapcar (lambda (n) (list n (luhn-check n)))
                '("1230"
                  "1231"
                  "1232"
                  "1233"
                  "1234"
                  "1235"
                  "1236"
                  "1237"
                  "1238"
                  "1239"
                  "25239")))

Which, thankfully, gives what look to be the correct answers below. Yes, I originally screwed up the check for odd/even digit. Yay tests.

Input Result
1230 t
1231 nil
1232 nil
1233 nil
1234 nil
1235 nil
1236 nil
1237 nil
1238 nil
1239 nil
25239 t

At any rate, what did I get to learn in this small exercise? Not much, to be honest. Seeing the lookup tables does show that 0 and 9 are unchanged in the branch, so I can see how these would not catch all transliterations easily.

Checking the Wikipedia page, I see there is also a weakness around some twin digits. That is not tough to see, but I am not sure that this method presents them more obviously than the other.

Author: Josh Berry

Created: 2021-02-05 Fri 23:51

Validate