Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is wrong with the following Common Lisp macro using gensym?

Learning Common Lisp (using GNU CLISP 2.43) .. so might be a noob mistake. Example is the 'print prime numbers between x and y'

(defun is-prime (n)
  (if (< n 2) (return-from is-prime NIL))

  (do ((i 2 (1+ i)))
      ((= i n) T)
    (if (= (mod n i) 0) 
        (return NIL))))

(defun next-prime-after (n)
  (do ((i (1+ n) (1+ i)))
      ((is-prime i) i)))

(defmacro do-primes-v2 ((var start end) &body body)
  `(do ((,var (if (is-prime ,start)
                  ,start
                  (next-prime-after ,start))
              (next-prime-after ,var)))
       ((> ,var ,end))
     ,@body))

(defmacro do-primes-v3 ((var start end) &body body)
  (let ((loop-start (gensym))
        (loop-end (gensym))) 
    `(do ((,loop-start ,start)
          (,loop-end ,end)
          (,var (if (is-prime ,loop-start)
                    ,loop-start
                    (next-prime-after ,loop-start))
                (next-prime-after ,var)))
         ((> ,var ,loop-end))
       ,@body )))

do-primes-v2 works perfectly.

[13]> (do-primes-v2 (p 10 25) (format t "~d " p))
11 13 17 19 23

Next I tried using gensym to avoid naming clashes in macro expansion - do-primes-v3. However I'm stuck with a

*** - EVAL: variable #:G3498 has no value

Tried using macro-expand to see if i could spot the mistake but I can't.

[16]> (macroexpand-1 `(do-primes-v3 (p 10 25) (format t "~d " p)))
(DO
 ((#:G3502 10) (#:G3503 25)
  (P (IF (IS-PRIME #:G3502) #:G3502 (NEXT-PRIME-AFTER #:G3502))
     (NEXT-PRIME-AFTER P)))
 ((> P #:G3503)) (FORMAT T "~d " P)) ;
like image 945
Gishu Avatar asked Feb 16 '09 13:02

Gishu


People also ask

What is a macro in Lisp?

Advertisements. Macros allow you to extend the syntax of standard LISP. Technically, a macro is a function that takes an s-expression as arguments and returns a LISP form, which is then evaluated.

What is so special about Lisp macros?

The special power that Lisp macros have is that they can control evaluation (as seen by evaluating the input expression via ~expr and do arbitrary source-to-source transformations with the full power of the language available.

Is a macro not a function Lisp?

Macros do code transformations at compile time or runtime. That's different from functions. Just look into the Common Lisp standard for many different pre-defined macros and their different syntax. Now think about, why these are macros and not functions.


1 Answers

Use DO* instead of DO.

DO Initializes the bindings in a scope where they are not yet visible. DO* initializes the bindings in a scope where they are visible.

In this particular case var needs to reference the other binding loop-start.

like image 89
kmkaplan Avatar answered Sep 28 '22 08:09

kmkaplan