Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does symbol-macrolet handle let shadowing?

From the CLHS

symbol-macrolet lexically establishes expansion functions for each of the symbol macros named by symbols.

...

The use of symbol-macrolet can be shadowed by let.

This allows the following code to work (inside *b* x is bound to '1'):

CT> (with-slots (x y z) *b* 
      (let ((x 10))
        (format nil "~a ~a ~a" x y z)))
"10 2 3"

My question is: How does symbol-macro let know which forms are allowed to shadow it? I ask as macros cannot guarentee that let has not been redefined or that the user has not created another form to do the same job as let. Is this a special 'dumb' case that just looks for the cl:let symbol? Or is there some more advance technique going on?

I am happy to edit this question if it is too vague, I am having difficulty articulating the issue.

like image 232
Baggers Avatar asked Jan 12 '23 10:01

Baggers


2 Answers

See 3.1.1.4 and the surrounding materials.

Where is that quote from? I don't think it's entirely correct, since let is not the only thing that can shadow the name established by macrolet in the lexical environment.

I don't think it does much harm to reveal that the lexical environment isn't just an abstract concept, there is an actual data structure that manifests it. The lexical environment is available to macros at compile time via the &environment binding mechanism. Macros can use that to get a window into the environment and there is a protocol for using the environment. So, to give a simple example, macros can be authored that are sensitive to declarations in the lexical environment, for example expanding one way if a variable is declared fixnum.

The implementation of the environment is left up to the implementers, but heh it is just stack of names with information about the names. So lambda bindings, macrolet, labels, let*, etc. etc. are merely pushing new names into that stack and thus shadowing the old names. And lexical declarations are adding to the information about the names.

The compiler or evaluator then uses the environment (stack) to guide how the resulting code or execution behaves. It's worth noting that this data structure need not survive into runtime, though often some descendent of it does to help the debugger.

So to answer you question: macrolet doesn't know anything about what forms in it's &body might be doing.

like image 175
Ben Hyde Avatar answered Jan 13 '23 23:01

Ben Hyde


As you can see SYMBOL-MACROLET is a built-in feature of Common Lisp. Just as LET. These special operators can't be redefined and it is not allowed to do so.

Common Lisp only has a fixed set of special operators and no way to define one by the user. There are only these ones defined: Common Lisp special operators.

Since macros will be expanded, they expand to the basic primitives: function calls and special forms. Thus the compiler/interpreter implements symbol-macrolet and this task is limited by the number of primitive forms. If the user implements his/her own LET, eventually this implementation boils also down to function calls and special forms - all uses of macros will be expanded to those, eventually. But those are known and there is nothing new for symbol-macrolet.

like image 36
Rainer Joswig Avatar answered Jan 13 '23 22:01

Rainer Joswig