From: ······@randallpub.com
Subject: Is this an appropriate use of closures?
Date: 
Message-ID: <1111495388.783856.77980@g14g2000cwa.googlegroups.com>
Thanks, everyone, for your additional comments.  I'm attempting to
summarize and test my knowledege again.

Lisp uses expressions involving lambda in (at least) the following
contexts:

   One   -- as "mere" quoted data.

   Two   -- as a macro, which wraps its argument into a function form.
The resulting function form will involve another use of lambda -- see
Three,  below.

   Three -- as an argument to function.  This use creates a
funcall'able / apply'able entity.

   Four  -- as a "lambda form", in the CAR of a list to be evaluated.
This use applys the function specified by the lambda form to the
arguments found in the rest of the list containing it.

Tests/samples of these four uses follow.

As quoted data:
(deftest test-lambda-as-quoted-data ()
   (check (equal '(lambda (x) (* 2 x)) (quote (lambda (x) (* 2 x))))))
0 checks failed, 1 check passed, 1 test.

as a  macro:
(deftest test-lambda-as-macro ()
   (check
      (equal (funcall (lambda (x) (+ x 1))   1)  2)
      (equal (apply   (lambda (x) (+ x 1)) '(1)) 2))
   (let ((add-two (lambda (x) (+ x 2))))
      (check
         (equal (funcall add-two 2) 4)
         (equal (apply add-two '(3)) 5))))
0 checks failed, 5 checks passed, 2 tests.

as an argument to function:
(deftest test-lambda-as-argument-to-function ()
   (check
      (equal (funcall (function (lambda (x) (+ x 1)))   1)  2)
      (equal (apply   (function (lambda (x) (+ x 1))) '(2)) 3)
      (equal (funcall         #'(lambda (x) (+ x 1))    3)  4)
      (equal (apply           #'(lambda (x) (+ x 1))  '(4)) 5))
   (let ((add-two (function (lambda (x) (+ x 2)))))
      (check
         (equal (funcall add-two 2) 4)
         (equal (apply add-two '(3)) 5)))
   (let ((add-three #'(lambda (x) (+ x 3))))
      (check
         (equal (funcall add-three 2) 5)
         (equal (apply add-three '(3)) 6))))
0 checks failed, 13 checks passed, 3 tests.

Finally, as a lambda form:
(deftest test-lambda-form ()
   (check
      (equal ((lambda (x) (+ x 2)) 3) 5)
      (equal ((lambda (x) (+ x 2)) 5) 7)))
0 checks failed, 15 checks passed, 4 tests.

Given the actions for the lambda MACRO, I now know that my next to last
original tests could have been written as:

(deftest test-random-elt ()
   (test-generator
      '(alfa bravo charlie delta echo)
      (lambda (x) (random-elt x))
      '(alfa bravo charlie delta echo)))

(deftest test-one-of ()
   (test-generator
      '( alfa   bravo   charlie   delta   echo)
      (lambda (x) (one-of x))
      '((alfa) (bravo) (charlie) (delta) (echo))))

(deftest test-article ()
   (test-generator
      '()
      (lambda (x) (article))
      '((a) (the))))

supported by:
(defun test-generator (inputs processor outputs)
   (let ((counts (make-hash-table :test #'equal))
         (total 0))

      ; zero out counts...
      (dolist (item outputs)
         (setf (gethash item counts) 0))

      ; generate 50 times, incrementing counts as we go...
      (dotimes (n 50)
         (incf (gethash (funcall processor inputs) counts)))

      ; now confirm that all entries are > 0 and that they total 50...
      (dolist (item outputs)
         (format t "~%~a: ~a" item (gethash item counts))
         (check (> (gethash item counts) 0))
         (incf total (gethash item counts)))
      (format t "~%")
      (check (equal total 50))))

Furthermore, the standard tells me that:

   (coerce '(lambda (x) (+ x 1)) 'function)

is equivalent to:

   (eval '(function (lambda (x) (+ x 1))))

So the last version of the tests above would work as:
(deftest test-random-elt ()
   (test-generator
      '(alfa bravo charlie delta echo)
      '(random-elt inputs)
      '(alfa bravo charlie delta echo)))

(deftest test-one-of ()
   (test-generator
      '( alfa   bravo   charlie   delta   echo)
      '(one-of inputs)
      '((alfa) (bravo) (charlie) (delta) (echo))))

(deftest test-article ()
   (test-generator
      '()
      '(article)
      '((a) (the))))

supported by:

(defun test-generator (inputs processor-expression outputs)
   (let ((processor
            (eval `(function (lambda (inputs) ,processor-expression))))
         (counts (make-hash-table :test #'equal))
         (total 0))

      ; zero out counts...
      (dolist (item outputs)
         (setf (gethash item counts) 0))

      ; generate 50 times, incrementing counts as we go...
      (dotimes (n 50)
         (incf (gethash (funcall processor inputs) counts)))

      ; now confirm that all entries are > 0 and that they total 50...
      (dolist (item outputs)
         (format t "~%~a: ~a" item (gethash item counts))
         (check (> (gethash item counts) 0))
         (incf total (gethash item counts)))
      (format t "~%")
      (check (equal total 50))))
-

Thanks again for your attention to, and help with, my questions.

David B. Ellis