I was playing with code generation outside macro being inspired by corrected version of nif

https://letoverlambda.com/index.cl/guest/chap3.html#sec_5

When I replace the usual gensym with my interned-gensym I can skip the eval and have more noob friendly version of the code that I can easily copy to REPL for further experiments with macro code creation. 

When it’s done, will I be able to replace with defmacro?

Why the usual gensym in macro is not interned?

Besides the eval is evil, what are other pitfalls of writing code this way?

(defun interned-gensym ()  
  "More suitable variant of gensym for macro experiments"  
  ;; file:~/Programming/sbcl/src/code/symbol.lisp::593  
  (values (intern (format nil "Z~A"
  (let ((old *gensym-counter*))
    (setq *gensym-counter* (1+ old))
    old)))))

;;; nif

(eval (apply (lambda (expr pos zero neg)
  (let ((gexpr (interned-gensym)))
    `(let ((,gexpr ,expr))
    (cond 
      ((plusp ,gexpr) ,pos)
      ((zerop ,gexpr) ,zero)
      (T ,neg)))))
    ;; args for the lambda
    ((- 5 2) :positive :zero :negative)))

  • stylewarning@alien.topB
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 year ago

    You’ll be able to essentially replace it with DEFMACRO, but it’s not 100% equivalent to do EVAL+APPLY. But the core idea is all the same: write code that creates valid S-expression forms.

    INTERNED-GENSYM is there just to make code easier to read and type, because using uninterned symbols #:LIKE-THIS are moderately tricky to get the hang of. It is not advised to ever actually use INTERNED-GENSYM because every macro expansion is going permanently allocate memory for new symbols, and these will never get garbage collected.

    At a higher level, the EVAL+APPLY way of doing things means that the lexical context (like previously bound variables) can’t be used, and all invocations of EVAL happen at run-time (not compile-time) so it would be excruciatingly slow.