Sample LA: Local bindings

Refactor redundancy and add clarity in computations with let-bindings.

Consider the following procedure that contains some repetitious code.

;;; (letter->number ch) -> either integer? boolean?
;;;   ch : char?
;;; Converts ch to the corresponding number in the English alphabet.
;;; (1 for #\a or #\A, 2 for #\b or #\B, etc.).  Returns false (#f)
;;; if ch is not a letter in the English alphabet.
(define letter->number
  (lambda (ch)
    (cond
      [(and (<= (char->integer #\a) (char->integer ch))
      	    (<= (char->integer ch) (char->integer #\z)))
       (+ 1 (- (char->integer ch) 97))]
      [(<= (char->integer #\a) (+ (char->integer ch) 32) (char->integer #\z))
       (+ 1 (- (+ (char->integer ch) 32) 97))]
      [else #f])))


(map letter->number (list #\a #\b #\c #\d #\e))
(1 2 3 4 5)

(map letter->number (list #\A #\B #\C #\D #\E))
(1 2 3 4 5)

(map letter->number (list #\X #\Y #\Z))
(24 25 26)

(letter->number #\.)
"Not a letter"

As you know, we should avoid redundant computations and magic numbers. Using local bindings (let or let*), remove the redundant computations and magic numbers from letter->number. You need not change the primary structure of the cond, but you should not compute the same value twice.

Note: In case you didn’t know, 32 is the result of subtracting the collating sequence number of #\A from the collating sequence number of #\a. By adding 32, we switch from uppercase to lowercase. And 97 seems to be the collating sequence number of #a, but we probably shouldn’t count on that.