So I hope there's a simple answer to this: how does one use a bareword in a macro? An iterate form for example looks like this:
Code: Select all
(iter (for item in list) ...)
Code: Select all
(iter (:for item :in list) ...)
Code: Select all
(iter (for item in list) ...)
Code: Select all
(iter (:for item :in list) ...)
You seem to be missing a point of macros. Macro is a function on source code, and so the symbols are passed as is, and not evaluated. In any case using keywords in function namespace wouldn't help anyway, as ":for" in not a function any more than "for".aerique wrote:While if I were to make an iterate macro I would have to give it the following syntax since my CL will otherwise complain about "for" not being a function and "in" being an unbound variable:
Basically "not a keyword". I tried to explain that with my two code examples.Ramarren wrote:I have never seen the word "bareword" used before and am fairly certain that it has no Lisp-specific meaning, so what do you mean exactly?
No, I don'tRamarren wrote:You seem to be missing a point of macros.
findinglisp wrote:As long as the compiler/interpreter never gets to the point where it actually tries to compile/interpret the FOR or IN forms, there is not a problem.
This is where I was having problems. However a simple test-case shows it to be as simple as you guys write:Ramarren wrote:Macro is a function on source code, and so the symbols are passed as is, and not evaluated. In any case using keywords in function namespace wouldn't help anyway, as ":for" in not a function any more than "for".
Code: Select all
(defmacro test (&rest args)
(dolist (arg args)
(format t "~S, ~S~%" (type-of arg) (symbol-name arg))))
CL-USER(15): (test a b c d)
SYMBOL, "A"
SYMBOL, "B"
SYMBOL, "C"
SYMBOL, "D"
NIL
Code: Select all
(defmacro iffy (condition &rest args)
(let ((state :then-or-else)
(then-forms nil)
(then-or-else-forms nil))
(dolist (arg (reverse args))
(cond ((equal (string-downcase (symbol-name arg)) "then")
nil)
((and (equal state :then-or-else)
(equal (string-downcase (symbol-name arg)) "else"))
(setf state :then))
((equal state :then)
(push arg then-forms))
((equal state :then-or-else)
(push arg then-or-else-forms))))
(if then-forms
`(if ,condition
(progn ,@then-forms)
(progn ,@then-or-else-forms))
`(if ,condition
(progn ,@then-or-else-forms)))))
Code: Select all
(STRING-EQUAL "foo" "FOO")
=> T
Code: Select all
(string-equal (symbol-name arg) "then")
All right, it looks like you are getting the hang of macros. Don't worry, these details confuse sometimes, specially in the beginning.aerique wrote:Alright, figured out what went wrong. I forgot to downcase the keywords during a comparison so instead of getting filtered out they did indeed get evaluated at a later moment. I was totally focussing on the wrong part of the macro when trying to find the problem.
Code: Select all
(equal (string-downcase (symbol-name arg)) "then")
Code: Select all
(eq arg :then)
Code: Select all
(case arg
(:then ...)
(:else ...))
This works with keywords, but will have problems if you want to use non-keyword symbols, because of problems with which package a given symbol is interned in. The OP is doing it correctly if he wants something more tolerant like the ITERATE syntax where it allows you to use either "THEN" or ":THEN" in the particular DSL you are creating. In this case, you're essentially just treating the symbol as a string and so it's appropriate to compare the symbol name. This avoids a wide range of possible problems. Besides, if this only runs at macro expansion time, it probably isn't performance sensitive.gugamilare wrote: Just a hint, if you are trying to see if the name of a keyword is "then", you don't need to compare strings. That's what symbols (and keywords, which are also symbols) are for. So, instead of:
you can justCode: Select all
(equal (string-downcase (symbol-name arg)) "then")
Or you can even use case:Code: Select all
(eq arg :then)
Code: Select all
(case arg (:then ...) (:else ...))