;;;; bottles4.lsp

;;; Solution ilustrating data and program equivalence
;;;

; What about having the following simple function? 
;
;(defun bottles ()
;  (progn
;    (format t "~a bottles of beer on the wall. " 4)
;    (format t "Take one down, and pass it around.~%")
;    (format t "3 bottles of beer on the wall. ")
;    (format t "Take one down, and pass it around.~%")
;    (format t "2 bottles of beer on the wall. ")
;    (format t "Take one down, and pass it around.~%")
;    (format t "1 bottle of beer on the wall. ")
;    (format t "Take one down, and pass it around.~%")
;    (format t "Now, they are all gone.")
;  ))
;
; Let's to construct it on-line and run subsequently.

(defun bottles (X)
 "Song '99 bottles on the wall'"
  (let ((s `(lambda () ,(generate X)) ))
      (funcall (coerce s 'function))))

(defun generate (X)
 "Preparation of the target function body"
  (cons 'progn (generate_aux X)))
(defun generate_aux (X)
  (cond ((zerop X)
	 (list (stock 0)))
	(t
	 (append (list (stock X) (take_one))
		 (generate_aux (1- X))))))

(defun take_one ()
 "Message for taking one bottle off" 
    '(format t "Take one down, and pass it around.~%"))

(defun stock (X)
 "Bottle status messages"
  (cond ((zerop X)
	 '(format t "Now, they are all gone."))
	((= X 1)
	 '(format t "1 bottle of beer on the wall. "))
	(t
	 `(format t "~a bottles of beer on the wall. " ,X))))
