最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

debugging - Undefined variable: COMMON-LISP-USER::0.25% in macro when I expected the symbol to not be evaluated - Stack Overflow

programmeradmin1浏览0评论

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"?!

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"?!

Share Improve this question edited Mar 30 at 18:25 Rainer Joswig 140k11 gold badges228 silver badges354 bronze badges asked Mar 30 at 12:51 GregFGregF 434 bronze badges 0
Add a comment  | 

2 Answers 2

Reset to default 2

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%))

set-value needs to call is-percent-p at macroexpansion time, not put the call in the expansion.

(defmacro set-value (value &optional frequency)
  (if (is-percent-p value)
      (let ((new-value (string-right-trim "%" (string value))))
        (/ (if (find #\. new-value)
               (parse-float:parse-float new-value)
               (parse-integer new-value :junk-allowed nil))
           100.0)
        new-value)
      value))

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论