(defun main-function (args)
(let ((local-variable (process-args args)))
(defun helper-function (x)
-- some function of local-variable --)
-- do some more processing --))
This creates a global binding for helper-function
and therefore is a case of a global side effect that is not
well documented. Never put a DEFUN inside a DEFUN.
The LAMBDA macro allows you to create local, unnamed functions
"on the fly."
;;; UGLY UGLY UGLY UGLY UGLY
(defun count-symbols (nested-list)
(let ((the-car NIL) ;; "Declarations" only
(the-cdr NIL) ;;
(symbols-in-car NIL) ;;
(symbols-in-cdr NIL)) ;;
(cond
((null nested-list) 0)
(T (setf symbols-in-car 0)
(setf the-car (car nested-list))
(if (symbolp the-car) (setf symbols-in-car 1))
(if (listp the-car) (setf symbols-in-car (count-symbols the-car)))
(setf symbols-in-cdr (count-symbols (cdr nested-list)))
(+ symbols-in-car symbols-in-cdr)))))
This is really bad Lisp style because there is no need to
"pre-declare" then set these variables. Here's a better way to write it: we let the different clauses of the COND separate the cases for us. In many cases doing that carefully allows fewer conditionals and local variables.
(defun count-symbols (nested-list)
(cond
((null nested-list) 0)
(T (let ((the-car (car nested-list))
(symbols-in-rest (count-symbols (cdr nested-list))))
(cond
((symbolp the-car) (+ 1 symbols-in-rest))
((listp the-car) (+ (count-symbols the-car) symbols-in-rest))
(T symbols-in-rest))))))
Here's another version that uses a conditional assignment to a variable.
It's open to debate whether this is good style or not. It's the
most purely "Lisp-like" of the three, but I personally find it a little
hard to read.
(defun count-symbols (nested-list)
(cond
((null nested-list) 0)
(T (let* ((the-car (car nested-list))
(symbols-in-car
(cond
((symbolp the-car) 1)
((listp the-car) (count-symbols the-car))
(T 0))))
(+ symbols-in-car (count-symbols (cdr nested-list)))))))