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
    ·
    10 months 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.

  • lispm@alien.topB
    link
    fedilink
    English
    arrow-up
    1
    ·
    10 months ago

    You might want to check the indentation of your code. It looks not right. Do you use TAB characters in your editor? Don’t!

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

    One problem could be, that your code is not working, because you have a bug in your EVAL form. Did you actually try to run it?

    Why the usual gensym in macro is not interned?

    Because then there is no name clash with symbols written by the macro user. If you would intern gensyms, where would you intern it? In which package Your variant does not say, whatever the current package is the symbol will be interned. If the user has a symbol there, one may get random (hard to debug) name clashes.

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

    EVAL is not ‘evil’. It’s just most of the time not needed and you need to understand what it does. EVAL evaluates the code always in the global environment. EVAL also may not compile the code, so it may run interpreted, depending on the Common Lisp implementation.

    • ruby_object@alien.topOPB
      link
      fedilink
      English
      arrow-up
      1
      ·
      10 months ago

      I could ensure I had no name clashes.

      However, my experiments have led me to understand double quoting. Seeing how level 1 quoting becomes unquoted and level 2 quoting becomes 1 one quoting and how once-only uses temporary variables gave me interesting insights. so while I will never use it in production, it was a very good experiment.