I have a macro to define initialization variables to the program. The macro is ...
(defmacro defparm (var value &key (frequency nil) (date nil date-supplied-p))
"Macro to define starting parameters."
`(let ((new-value (set-value ,value ,frequency)))
(cond ((eq ,date-supplied-p t)
(set-variation ',var new-value (make-date ,date)))
(t (setf (slot-value *my-parms* ',var) new-value)))))
This macro depends on macros set-value and set-variation, and functions is-date-p and is-percent-p.
(defun is-percent-p (value)
(cond ((and (symbolp value) (char= (char (symbol-name value) (1- (length (symbol-name value)))) #\%)))
((and (stringp value) (char= (char value (1- (length value))) #\%)))
(t nil)))
(defmacro set-value (value &optional frequency)
`(cond ((and (typep ',value 'symbol) (is-percent-p ',value))
(let ((new-value (string-right-trim "%" (symbol-name ',value))))
(/ (if (find #\. new-value)
(parse-float:parse-float new-value)
(parse-integer new-value :junk-allowed nil)) 100.0)))
(t ,value)))
I haven't included is-date-p because it isn't relevant in this situation, and set-variation can simply be dummied out ...
(defun set-variation (&rest x)
(declare (ignorable x)))
When I evaluate ...
(defparm interest-rate 5%)
I get this ...
(defparm interest-rate 5%) ; in: DEFPARM INTEREST-RATE ; (SET-VALUE 5% NIL) ; --> IF IF AND IF TYPEP ; ==> ; 1 ; ; caught WARNING: ; undefined variable: COMMON-LISP-USER::5% ; ; compilation unit finished ; Undefined variable: ; 5% ; caught 1 WARNING condition 0.05 0.05
The result is correct, 0.05, but I don't understand why I get the warning.
I have put in (print nn) statements in an attempt to pin down where the warning occurs, where the '5% symbol is evaluated, but I can't find it.
Where in my code is the actual point of the "warning"?!
If we expand your expression fully ("walk"), then we get something like this:
(LET ((NEW-VALUE
(COND ((IF (TYPEP '5% 'SYMBOL) (IS-PERCENT-P '5%) NIL)
(LET ((NEW-VALUE (STRING-RIGHT-TRIM "%" (SYMBOL-NAME '5%))))
(/ (IF (FIND #\. NEW-VALUE)
(PARSE-FLOAT NEW-VALUE)
(PARSE-INTEGER NEW-VALUE :JUNK-ALLOWED NIL))
100.0)))
(T 5%))))
(COND ((EQ NIL T) (SET-VARIATION 'INTEREST-RATE NEW-VALUE (MAKE-DATE NIL)))
(T (CLOS::SET-SLOT-VALUE *MY-PARMS* 'INTEREST-RATE NEW-VALUE))))
You can see that in your first cond
there is a clause (t 5%)
. That's where 5%
is a variable.
Typically I would debug these things by macro expanding the corresponding code snippets (and optionally a compiler would give me undefined variable locations, etc.):
CL-USER 9 > (pprint (macroexpand-1 '(SET-VALUE 5% NIL)))
(COND ((AND (TYPEP '5% 'SYMBOL) (IS-PERCENT-P '5%))
(LET ((NEW-VALUE (STRING-RIGHT-TRIM "%" (SYMBOL-NAME '5%))))
(/ (IF (FIND #\. NEW-VALUE)
(PARSE-FLOAT NEW-VALUE)
(PARSE-INTEGER NEW-VALUE :JUNK-ALLOWED NIL))
100.0)))
(T 5%))