Why is macro expansion given a free pass at evaluation? [duplicate] - macros

This question already has answers here:
Why does foo have the same value as (foo) in this Racket macro?
(3 answers)
Closed last month.
I was reading Greg Hendershott's Fear of Macros and I stumbled into this code:
(define-syntax foo
(λ (stx)
(syntax "I am foo")))
Which seems quite innocent, but I notice that either on the REPL or as part of the source code, it's irrelevant whether I write a foo expansion with or without parentheses:
> foo
"I am foo"
> (foo)
"I am foo"
>
Which is odd, because If I enter things directly at the REPL:
> "I am foo"
"I am foo"
> ("I am foo")
. . application: not a procedure;
expected a procedure that can be applied to arguments
given: "I am foo"
>
I get an error when trying to call the string w/o parentheses because the string is already an irreducible constant.
So, the question I have is why does this happen?
So, any info would be appreciated.
Thanks
Research I have done so far:
I looked in the macro stepper and saw that the macro is wrapped several times by do-wrapping-module-begin, but I have no idea how that behaves.
(do-wrapping-module-begin
print-result
(define-syntax foo (λ (stx) (syntax "I am foo"))))
(do-wrapping-module-begin print-result foo)
(do-wrapping-module-begin print-result (foo))))

This definition:
(define-syntax foo
(λ (stx)
(syntax "I am foo")))
binds foo to the syntax transformer (λ (stx) (syntax "I am foo")).
When the macro foo is invoked, the syntax transformer is called
with an argument: the expression that invoked the macro.
Now, there are several ways of invoking a macro.
The usual one, is: (foo 42) which will call the syntax transformer
with the argument (syntax (foo 42)). In our example the transformer
ignores its input (stx) and returns (syntax "I am foo") so
the macro call (foo 42) will be replaced with "I am foo".
Another way of invoking a macro is as a reference: If foo occurs
alone, then the syntax transformer will be called with (syntax foo)
as argument. Since the transformer ignores the input, the the reference will
be replaced with "I am foo".
The third way of invoking a syntax transformer is when foo is used in an
assignment as in (set! foo 42). See "identifier macro" in the docs.
Tip: To check that the description above is what actually takes place, you can make the transformer print its argument.
(define-syntax foo
(λ (stx)
(displayln (syntax->datum stx))
(syntax "I am foo")))

Related

Why can't I customize the application of a struct-id construction function?

I would like to build a custom language in Racket that requires redefining the implicit form #%app. However, using the macro stepper I noticed that unlike regular "proc-id" function application, struct-id application does not get replaced with the custom #%app form. Why is this the case?
My guess is that what you are seeing in the macro stepper is a result of the fact that (unless you specify otherwise with keyword options) struct binds the struct name to a macro to communicate static information about the struct type, which is used by match, shared, struct-out, and other macros. When used as an expression, this macro expands to the constructor function, which is bound to an otherwise-inaccessible name. If that doesn't seem to explain what you're seeing, perhaps you could give a code example.
In any case, if you disable macro hiding, you will see that direct application of the constructor function does use the correct #%app form. For example, this program:
#lang racket
(module language racket
(provide (rename-out [my-app #%app])
(except-out (all-from-out racket)
#%app))
(define-syntax-rule (my-app rator rand ...)
(let ()
(print-app-form '(rator rand ...))
(rator rand ...)))
(define (print-app-form quoted)
(printf "; ~a\n" quoted)))
(module main (submod ".." language)
(struct bag (contents)
#:transparent)
(define groceries
'(oranges milk salsa))
(bag groceries))
prints the following output, where bag1 is an artifact of #%app being expanded after the bag macro:
; (bag1 groceries)
(bag '(oranges milk salsa))

pass a list to macro in Common Lisp

I'm having a problem passing a list to macro, where the list will be used to generate function name. For example, the code below causes an error.
(defmacro gen (str-lst)
`(defun ,(intern (string-upcase (car str-lst))) () (print "foo")))
(gen '("foo" "bar"))
The resulting error was:
*** - DEFUN/DEFMACRO: QUOTE is a special operator and may not be redefined. The following restarts are available: ABORT :R1
Abort main loop
How should I modify my code, and what is wrong with my code?
The thing makes me even more confused is that the code below, about which answer exits here, works fine.
(defmacro easy-one (str-lst)
`(mapc #'(lambda (str) (print str)) ,str-lst))
(easy-one '("foo" "bar"))
Don't quote the list. Macros don't evaluate their arguments, so you don't need to quote them to prevent them from being evaluated, like you do for ordinary functions.
(gen ("foo" "bar"))
When you quote it, you're executing
(get (quote ("foo" "bar")))
The value of str-list is the list (quote ("foo" "bar")), so (car str-list) is the symbol QUOTE. As a result, the macro expands to
(defun quote () (print "foo"))
That's why you get an error complaining that you're trying to redefine the built-in QUOTE.
The difference in your second example is that you're just substituting the parameter into the expansion, you're not using its value in the expansion code. So it expands to
(mapc #'(lambda (str) (print str)) '("foo" "bar")))
Here the list will be used when the expansion runs, not while the macro is being expanded. It needs to be quoted there, to prevent it from being evaluated as a function call.
You should use macroexpand to see how your macros are being expanded when debugging.

Overriding "this" identifier macro in Racket

I made my own prototypal OO system in Racket which uses "this" for methods. Everything works great, but unfortunately it prevents Racket's native class system from using "this".
Here's what I want to do:
(require (only-in racket (this oldthis)))
(define-syntax this
(syntax-id-rules (set!)
((set! this ...) (void))
((this a ...) ((self) a ...))
(this (if (null? (self)) oldthis (self)))))
One thing I've tried to do is rename the above "this" macro to be "newthis" and make a helper macro as follows:
(define-syntax (this stx)
(syntax-case stx ()
(this #'(if (null? (self)) oldthis newthis))))
But in both cases Racket throws an error because I'm using "oldthis" outside of a class context. How do I merely reference the old "this" macro without expanding it and throwing an error? Or, more broadly, how can I make my "this" macro delegate to the old "this" macro when (self) is null?
Thanks in advance!
EDIT: Here is some code that uses "this" properly:
(define Foo (new))
(void (# Foo 'name "Foo")
(# Foo 'method (lambda () (# this 'name))))
You can then run Foo's "method" by calling
((# Foo 'method))
Which gives the correct result "Foo"
However, if I use Racket's class system:
(define foo%
(class object%
(super-new)
(define/public (displayself)
(displayln this))))
and run
(define foo (make-object foo%))
(send foo displayself)
I get (), always, since "this" returns (self) and (self) has in its closure a value "self" which is currently null. What I want to do is to check if (self) is null and, if it is, delegate to the built-in "this" macro.
EDIT2:
It looks like this answer is doing what I want to do. When I try it, however, I still get the same error about class context. I think the reason for that is that the #%top macro is invoked by (real-top . rest) and not by real-top on its own. In my case, however, oldthis gets invoked immediately and throws the error. I have no idea how to prevent that.
One thing I did that got close was to enclose oldthis in (eval 'oldthis), but that only worked in the current namespace. In order for that to work consistently, I would have to provide oldthis in conjunction with everything else, which is not only ugly but error prone, since an unsuspecting user of the library wouldn't necessarily understand that they have to pass oldthis all the time for anything to work properly. So I don't want to do it this way.
SOLVED:
(define-syntax this
(syntax-id-rules (set!)
((set! this ...) (void))
((this a ...) ((self) a ...))
(this (if (null? (self)) (eval 'this (module->namespace 'racket)) (self)))))
By providing the racket language as the namespace argument for eval, I can reference the old "this" without making any assumptions about the program using my OO library except that it have access to the racket language.
You should be able to do this directly with rename-in. Take the following code for example:
#lang racket
(require (rename-in racket [this old-this]))
(define this 42)
(define foo%
(class object%
(super-new)
(define/public (get-me)
old-this)))
(define bar (new foo%))
(send bar get-me)
Here we use rename-in to import old-this to point to the same binding as this in Racket. Which is needed because we immediately shadow that binding with: (define this 42)
Next, we define the foo% object, with one method: get-me, which just returns the current object with this (or specifically old-this.
Finally, we define a new foo% called bar, and call get-me. As you can see, it returns the bar object as you would expect.
If, instead of old-this, you returned this, then get-me would return 42, because of the definition. Likewise, if you removed the definition for this as 42, then this would still be bound to the one the class macro expects.

Confusing clojure macro var evaluation

I am trying to write a clojure macro that transforms clojure keywords to java enums. But the evaluation of the parameters in a macro is confusing:
user=> (defmacro show-and-tell [thing]
#_=> `(vector ~(name thing) ~(type thing) ~thing))
#'user/show-and-tell
user=> (macroexpand-1 (show-and-tell :foo))
["foo" clojure.lang.Keyword :foo]
user=> (def foo :bar)
#'user/foo
user=> (name foo)
"bar"
user=> (type foo)
clojure.lang.Keyword
user=> (macroexpand-1 (show-and-tell foo))
["foo" clojure.lang.Symbol :bar]
So it works as I would expect if the keyword is provided directly as a parameter. But if it is a var, I don't get the correct name and type of the thingy.
I can make it 'sort-of-almost' work by using eval:
user=> (defmacro show-and-tell-with-eval [thing]
#_=> `(vector ~(name (eval thing)) ~(type (eval thing)) ~(eval thing)))
#'user/show-and-tell-with-eval
user=> (macroexpand-1 '(show-and-tell-with-eval foo))
(clojure.core/vector "bar" clojure.lang.Keyword :bar)
user=> (let [baz :bar-foo] (macroexpand-1 '(show-and-tell baz)))
(clojure.core/vector "baz" clojure.lang.Symbol baz)
user=> (let [baz :bar-foo] (macroexpand-1 '(show-and-tell-with-eval baz)))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: baz in this context
Can someone explain this to me? Is there no way to see the name of a (local) var inside a macro?
You might wanted to write
(defmacro show-and-tell [thing] `(vector (name ~thing) (type ~thing) ~thing))
Ad-hoc explanation:
The key to understand what's going on is to know when the arguments are evaluated. Macros take unevaluated data structures as arguments and return a data structure which is then evaluated using the rules above. Using the ~ you tell the compiler which data structures should be evaluated at runtime, thus, your thing argument, not the return value of (name thing) value as the thing value will be bound at compile time in the latter case which is not what you wanted
Here you have a further explanation about writing macros http://www.braveclojure.com/writing-macros/
You seem to be confused about the relation between vars and what they contain and how macros come into play. "Vars provide a mechanism to refer to a mutable storage location" (cf. the offical docs on Vars). When you evaluate foo in the REPL, Clojure will evaluate it according to the rules outlined in the offical docs for evaluation which in this case means, it resolves the symbol to "the value of the binding of the global var named by the symbol".
Now, it's crucial to understand that macros "are functions that manipulate forms, allowing for syntactic abstraction". Basically macros allow direct access to any parameter handed to the macro and then manipulate and evaluate the related data as needed. Let's take a glance at your macro and what happens in your "erroneous" case:
(defmacro show-and-tell [thing]
`(vector ~(name thing) ~(type thing) ~thing))
Your macro definition gets fed some thing (whatever is the parameter to show-and-tell). At this point, thing will not be resolved. Only in your macro definition you have some evaluations. Please note that in this call, you're calling macroexpand-1 on the (evaluated) result of (show-and-tell foo) which is probably not what you want:
user=> (macroexpand-1 (show-and-tell foo))
["foo" clojure.lang.Symbol :bar]
Quoting the call shows what's going on:
user=> (macroexpand-1 '(show-and-tell foo))
(clojure.core/vector "foo" clojure.lang.Symbol foo)
You're calling vector with "foo" (i.e. the name of foo) where foo is a symbol and then your code will resolve foo normally (and give :bar).
From your description, you seem to expect that normal symbol resolution will take place for all your arguments. If this is what you want, you don't need a macro in the first place. But just for the record, by now it should be obvious what you need to do: you need to evalute thing first (which is pretty much what you did with eval). In other words, you placed your unquote operator wrong:
(defmacro show-and-tell [thing]
`(vector (name ~thing) (type ~thing) ~thing))
user=> (macroexpand-1 '(show-and-tell foo))
(clojure.core/vector (clojure.core/name foo) (clojure.core/type foo) foo)
user=> (show-and-tell foo)
["bar" clojure.lang.Keyword :bar]

lisp macro expand with partial eval

I have following code which confuse me now, I hope some can tell me the difference and how to fix this.
(defmacro tm(a)
`(concat ,(symbol-name a)))
(defun tf(a)
(list (quote concat) (symbol-name a)))
I just think they should be the same effect, but actually they seem not.
I try to following call:
CL-USER> (tf 'foo)
(CONCAT "FOO")
CL-USER> (tm 'foo)
value 'FOO is not of the expected type SYMBOL.
[Condition of type TYPE-ERROR]
So, what's the problem?
What i want is:
(tm 'foo) ==> (CONCAT "FOO")
The first problem is that 'foo is expanded by the reader to (quote foo), which is not a symbol, but a list. The macro tries to expand (tm (quote foo)). The list (quote foo) is passed as the parameter a to the macro expansion function, which tries to get its symbol-name. A list is not a valid argument for symbol-name. Therefore, your macro expansion fails.
The second problem is that while (tm foo) (note: no quote) does expand to (concat "FOO"), this form will then be executed by the REPL, so that this is also not the same as your tf function. This is not surprising, of course, because macros do different things than functions.
First, note that
`(concat ,(symbol-name a))
and
(list (quote concat) (symbol-name a))
do the exact same thing. They are equivalent pieces of code (backquote syntax isn't restricted to macro bodies!): Both construct a list whose first element is the symbol CONCAT and whose second element is the symbol name of whatever the variable A refers to.
Clearly, this only makes sense if A refers to a symbol, which, as Svante has pointed out, isn't the case in the macro call example.
You could, of course, extract the symbol from the list (QUOTE FOO), but that prevents you from calling the macro like this:
(let ((x 'foo))
(tm x))
which raises the question of why you would event want to force the user of the macro to explicitly quote the symbol where it needs to be a literal constant anyway.
Second, the way macros work is this: They take pieces of code (such as (QUOTE FOO)) as arguments and produce a new piece of code that, upon macroexpansion, (more or less) replaces the macro call in the source code. It is often useful to reuse macro arguments within the generated code by putting them where they are going to be evaluated later, such as in
(defmacro tm2 (a)
`(print (symbol-name ,a)))
Think about what this piece of code does and whether or not my let example above works now. That should get you on the right track.
Finally, a piece of advice: Avoid macros when a function will do. It will make life much easier for both the implementer and the user.