Differences between Sharpsign Colon and Gensym

I just read the macro of the reader with a clear image, and it sounded like it was very similar to gensym

Sharpsign Colon: "enter character without character"

Gensym: "Creates and returns a new, uninterrupted character"

So a simple test

CL-USER> #:dave ; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {1002FF77D3}>. CL-USER> (defparameter #:dave 1) #:DAVE CL-USER> #:dave ; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {100324B493}>. 

Cool so it doesn't work.

Now for the macro test

 (defmacro test (x) (let ((blah '#:jim)) `(let ((,blah ,x)) (print ,blah)))) CL-USER> (test 10) 10 10 CL-USER> 

Sweet, so it can be used, as in ingenious form.

For me it looks cleaner than gensym with a clearly identical result. I am sure that I am missing an important detail, so my question is: what is it?

+5
source share
2 answers

GENSYM is similar to MAKE-SYMBOL . The difference is that GENSYM supports fancy naming by counting →, so the characters have unique names, which makes debugging easier with gensyms, for example, in macro decompositions.

#:foo is a designation for the reader.

So, you have a function that creates these and literary notations. Note that when *print-circle* true, some type of identity can be stored in s-expressions: #(#1=#:FOO #1#) .

Typically, this is similar to (a . b) and (cons 'a 'b) , #(ab) and (vector 'a 'b) ... One is literal data, and the other is the form that will create ("cons") fresh objects.

If you look at your macro, the main problem is that its nested use can cause problems. Both lexically and dynamically.

  • Lexically, it can be the same variable that is being restored.

  • dynamically, if it is a special variable, it can also be a rebound

Using the generated character while increasing the macro time will ensure that different and extended code will not transmit bindings.

+6
source

Each time a macro expands, it will use the same character.

 (defmacro foo () `(quote #:x)) (defmacro bar () `(quote ,(gensym))) (eq (foo) (foo)) => t (eq (bar) (bar)) => nil 

Gensym will create a new character every time it is evaluated, but a clear colon will only create a new character after reading it.

Using a sharp colon is unlikely to cause problems; there are a few rare cases where using it will make it almost impossible to find errors. It's best to be safe to start with, always using gensym.

If you want to use something like a strong colon, you should look at the defmacro macro ! from Let Over Lambda.

+8
source

Source: https://habr.com/ru/post/1212422/


All Articles