pass a list to macro in Common Lisp - macros

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.

Related

How can I create a `with-eval-after-load-all` in Emacs Lisp?

I'm trying to create something similar to with-eval-after-load except that the body evaluates after all features have been provided. Additionally, the feature list must be provided at runtime.
For example, I want something like
(setq feature-list '(a b))
(something feature-list (message "a and b both provided"))
where this performs functionality equivalent to
(with-eval-after-load 'a
(with-eval-after-load 'b
(message "a and b both provided")))
Providing the list at runtime seems to be the tricky part. Without that requirement I could write a macro:
(defmacro eval-after-load-all (features body)
(if (null features)
body
`(with-eval-after-load (quote ,(car features))
(eval-after-load-all ,(cdr features) ,body))))
and pass the list with:
(eval-after-load-all (a b) (message "a and b both provided"))
But passing it feature-list will cause it to use the literal characters "feature-list".
I've tried defining a recursive function:
(defun eval-after-load-all (features body)
(if (null features)
body
(with-eval-after-load (car features)
(eval-after-load-all (cdr features) body))))
But when I evaluate
(eval-after-load-all feature-list (message "a and b both provided"))
(provide 'a)
;; (provide 'b)
It triggers an error at the (provide 'a) call complaining about void-variable body in the recursive call step (i.e. last expression in the function). This scope confuses me. Why is body void here?
I also tried to wrap the macro in a function so that I could pass it the evaluated arguments:
(defun macro-wrapper (features body)
(eval-after-load-all features body))
but this complains at function definition that features is not a list: wrong-type-argument listp features.
You may not use the symbol features as an argument since that is (I cite the doc of features):
A list of symbols which are the features of the executing Emacs.
Used by featurep and require, and altered by provide.
The following code for eval-after-load-all works as expected. It is derived from your recursive function definition.
I added the evaluation of the form as function or as expression with funcall or eval, respectively, I used the backquote for the lambda, and I introduced the quoting for the list and the expression in the generated lambda expression.
(defun eval-after-load-all (my-features form)
"Run FORM after all MY-FEATURES are loaded.
See `eval-after-load' for the possible formats of FORM."
(if (null my-features)
(if (functionp form)
(funcall form)
(eval form))
(eval-after-load (car my-features)
`(lambda ()
(eval-after-load-all
(quote ,(cdr my-features))
(quote ,form))))))

Defining a macro to take an input stream

I'm attempting to make a macro that will take an input stream and do something different depending on the contents of the first line read, and then read further input. I'm having trouble just having a macro that will take an input stream and read some values from it.
A contrived example:
(defmacro read-and-print (&optional in)
`(print
,(if (string= (read-line in) "greet")
`(concatenate 'string "hello" (read-line ,in))
`(read-line ,in))))
(with-input-from-string (in "greet
bob") (read-and-print in))
but even that is producing the following error
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION SB-GRAY:STREAM-READ-LINE (1)>
when called with arguments
(IN).
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
The thing that's really baffling me is even changing the function to take a string for the first line isn't working:
(defmacro read-and-print (command &optional in)
`(print
,(if (string= command "greet")
`(concatenate 'string "hello " (read-line ,in))
`(read-line ,in))))
(with-input-from-string (in "greet
bob")
(read-and-print (read-string in) in))
This gives me
The value
(READ-LINE IN)
is not of type
(OR (VECTOR CHARACTER) (VECTOR NIL) BASE-STRING SYMBOL CHARACTER)
when binding SB-IMPL::STRING1
[Condition of type SB-INT:COMPILED-PROGRAM-ERROR]
While this executes completely fine:
(with-input-from-string (in "greet
bob")
(read-and-print "greet" in))
Is there something special about the with-input-from-string macro that I'm missing? I suspect I'm missing something very obvious about macros, but googling has gotten me nowhere.
What you asked
Macros are a code generation tool.
They do not evaluate their arguments.
Your with-input-from-string example works because strings are self-evaluating. If you quite the string literal, you will get an error.
What you should have asked
You do not need a macro here. Use a function instead.
When deciding between a function and a macro, you need to ask yourself:
Am I defining a new syntax?
Does the code generate more code?
Unless you understand the questions and answer yes, you should be using functions.
See also How does Lisp let you redefine the language itself?
Your macro:
(defmacro read-and-print (&optional in)
`(print
,(if (string= (read-line in) "greet")
`(concatenate 'string "hello" (read-line ,in))
`(read-line ,in))))
But ,(if ... in ...) makes no sense, since the value of in typically isn't a stream at macro expansion time, but code (a symbol, an expression, ...). Since your code is not executing and the macro sees the source (and not the values of something which has not been executed yet) you can't do that. You can't also not usefully repair that: It's just the wrong approach. Use a function instead.
Use a function:
CL-USER 17 > (defun read-and-print (&optional in)
(if (string= (read-line in) "greet")
(concatenate 'string "hello" (read-line in))
(read-line in)))
READ-AND-PRINT
CL-USER 18 > (with-input-from-string (in "greet
foo
bar")
(read-and-print in))
"hellofoo"
Using a macro
You still can write it as a macro, but then you need to generate the code so that it runs at runtime, and not at macro-expansion time:
(defmacro read-and-print (&optional in)
`(print
(if (string= (read-line ,in) "greet")
(concatenate 'string "hello" (read-line ,in))
(read-line ,in))))
Note: one would actually might want to handle that in is not evaluated multiple times.
This macro would give you the advantage that the code is inlined.
This macro would give you the disadvantage that the code is inlined.
The function above gives you the advantage that the code typically is not inlined.
The function above gives you the advantage that the code can optionally be inlined, by telling the compiler to do so with an inline declaration.

Can I put condition in emacs lisp macro?

How to achieve something like this?
(defmacro mood (x)
(if (equal (symbol-name x) "t")
`(defun happy ()
(message "Happy"))
`(defun sad ()
(message "Sad")))
)
My aim is to create different function base on argument.
Is there any problem doing so?
Edit 2: You're right -- for cases in which the code being evaluated at expansion-time is entirely dependent on the values of the (unevaluated) macro arguments, I believe it is safe for the macro's returned form to be generated conditionally, based upon those arguments.
You just need to be aware that any behaviour which is conditional upon dynamic values needs to be dealt with as a part of the expanded form.
(e.g. if the macro argument were a variable, and you were testing the value of the variable in your condition, it would be unsafe for that test to occur at expansion time, as that value is liable to vary between the macro's expansion time, and the time(s) that the expanded code is evaluated.)
So the specific example in your question is indeed safe as-is, and therefore my variations (below) are not actually necessary in this case. However expansion-time evaluations are certainly something you will want to be cautious about in general.
Initial answer follows...
Macros are expanded at compile time. (Or in recent versions of Emacs, should no byte-compiled version of the library be available, they will usually be compiled "eagerly" at load time).
In these scenarios, any code which is not a part of the form returned by the macro will be evaluated at most once per session, but quite likely just once ever for a given expansion of the code (whereas the expanded code might then be called numerous times).
If you need your expanded code to act conditionally at run-time, the conditions must be a part of the form returned by the macro.
Edit: For example, I imagine you actually wanted to write something more like:
(defmacro mood (x)
`(if (equal (symbol-name ,x) "t")
(defun happy ()
(message "Happy"))
(defun sad ()
(message "Sad"))))
Although you would (almost) never want to compare symbols by comparing their symbol-name. You've already made the assumption that the macro argument will evaluate to a symbol, so just compare the symbols directly with eq:
(defmacro mood (x)
`(if (eq ,x t)
(defun happy ()
(message "Happy"))
(defun sad ()
(message "Sad"))))
Then for example, (mood 'foo) expands to (courtesy of M-x pp-macroexpand-last-sexp):
(if
(eq 'foo t)
(defun happy nil
(message "Happy"))
(defun sad nil
(message "Sad")))
There is no problem defining it. You code, actually, almost works:
(defmacro mood (x)
(if (equal x t)
`(defun happy ()
(message "Happy"))
`(defun sad ()
(message "Sad"))))
Since if is outside of back-quotes, we can examine the value of x directly. Expanding this definition with different arguments shows that different functions are defined:
> (macroexpand '(mood t))
(defalias (quote happy) (function (lambda nil (message "Happy"))))
> (macroexpand '(mood nil))
(defalias (quote sad) (function (lambda nil (message "Sad"))))

Common Lisp Lisp-1 macro

I am trying to emulate the single namespace of scheme within common lisp, with a macro (based on Doug Hoyte's) that expands to a lambda, where every use of an f! symbol (similar to Doug Hoyte's o! and g! symbols) in the function position expands to the same expression, but with funcall added in the function position of each invocation. For example:
(fplambda (f!z x) (f!z x x))
would expand to:
(LAMBDA (F!Z X) (FUNCALL F!Z X X))
The macro currently looks like this:
(defmacro fplambda (parms &body body)
(let ((syms (remove-duplicates
(remove-if-not #'f!-symbol-p
(flatten body)))))
`(lambda ,parms
(macrolet ,(mapcar
(lambda (f)
`(,f (&rest parmlist) `(funcall ,',f ',#parmlist)))
syms))
,#body)))
but given the above input, it expands (as far as I can see) to this:
(LAMBDA (F!F X)
(MACROLET ((F!F (&REST PARMLIST) `(FUNCALL ,'F!F ',#PARMLIST))))
(F!F X X))
In the macrolet definition, F!F should not be quoted or unquoted, and parmlist should just be unquoted. What is going on?
Thanks in advance!
Your definition is mostly right. You just made two pretty simple mistakes. The first one being a mismatched paren. The macrolet does not include the body (in the output the macrolet and the body are at the same level of indentation).
As for the nested backquote, the only mistake is the quote before parmlist. Other than that everything else is correct. The comma and quote before F!F is actually correct. From the hyperspec:
"An implementation is free to interpret a backquoted form F1 as any form F2 that, when evaluated, will produce a result that is the same under equal as the result implied by the above definition". Since the inner backquote has not been expanded yet, it does not have to be free of quotes and unquotes. The expression `(,'x) is actually the same as `(x).
Nested backquotes are notoriously complicated. What is probably the easiest way to understand them is to read Steele's explanation of them.
Edit:
The answer to your question about whether it is possible to use a fplambda expression in the function position is no. From the part of the hyperspec that deals with the evaluation of code: "If the car of the compound form is not a symbol, then that car must be a lambda expression, in which case the compound form is a lambda form.". Since the car of the form, (fplambda ...), is not a lambda expression, your code is no longer valid Common Lisp code.
There is a workaround to this that I figured out, but it's kind of ugly. You can define a reader macro that will allow you to write something like ([fplambda ...] ...) and have it read as
((LAMBDA (&REST #:G1030) (APPLY (FPLAMBDA ...) #:G1030)) ...)
which would do what you want. Here is code that will allow you to do that:
(set-macro-character #\[ 'bracket-reader)
(set-macro-character #\] (get-macro-character #\)))
(defun bracket-reader (stream char)
"Read in a bracket."
(declare (ignore char))
(let ((gargs (gensym)))
`(lambda (&rest ,gargs)
(apply ,(read-delimited-list #\] stream t)
,gargs))))
The only other solution I can think of would be to use some sort of code walker (I can't help you there).

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.