Using barewords not keywords in macros

Discussion of Common Lisp

Using barewords not keywords in macros

Postby aerique » Fri Apr 17, 2009 8:42 am

If been trying to figure something out and neither Google has been much help nor did looking at the source for the iterate package help me. It only made me more confused.

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) ...)

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:

Code: Select all
(iter (:for item :in list) ...)
aerique
 
Posts: 10
Joined: Sat Jun 28, 2008 9:06 am

Re: Using barewords not keywords in macros

Postby findinglisp » Fri Apr 17, 2009 9:07 am

Whenever the compiler/interpreter encounters ITER in the first position of a list, it immediately starts to process it as a macro. It passes all the rest of the macro form (everything that follows ITER) to the ITER macro, uninterpreted. Therefore, the compiler never has to determine whether FOR or IN are bound to functions or other values. In other words, everything in the body of the ITER form is just raw data at that point. Once all that is passed to ITER, the macro has a chance to examine all its parameters and return another form to replace the ITER form. The compiler/interpreter then repeats the same process on the returned form (which may also be a macro and invoke yet another macro expansion). 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. They are simply raw symbols that are interpreted by the ITER macro at macro expansion time.
Cheers, Dave
Slowly but surely the world is finding Lisp. http://www.findinglisp.com/blog/
findinglisp
 
Posts: 440
Joined: Sat Jun 28, 2008 7:49 am
Location: Austin, TX

Re: Using barewords not keywords in macros

Postby Ramarren » Fri Apr 17, 2009 9:10 am

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?

Also, iterate macro as defined in iterate library is a perfectly normal macro written in more or less portable Common Lisp, and so you can do anything it does.

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:


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".
Ramarren
 
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland

Re: Using barewords not keywords in macros

Postby aerique » Fri Apr 17, 2009 3:00 pm

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?

Basically "not a keyword". I tried to explain that with my two code examples.

Ramarren wrote:You seem to be missing a point of macros.

No, I don't :)

I just have next to no experience writing them and these are some of the issues I'm running into.

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.

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".

This is where I was having problems. However a simple test-case shows it to be as simple as you guys write:

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

So, I have no idea where it went wrong with the macro I was working on. I don't have it at hand at the moment though :(
aerique
 
Posts: 10
Joined: Sat Jun 28, 2008 9:06 am

Re: Using barewords not keywords in macros

Postby aerique » Fri Apr 17, 2009 3:34 pm

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.

I hereby present Iffy!:

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)))))

(no worries, it was just an excercise in writing macros :lol:)
aerique
 
Posts: 10
Joined: Sat Jun 28, 2008 9:06 am

Re: Using barewords not keywords in macros

Postby findinglisp » Fri Apr 17, 2009 5:24 pm

Rather than dealing with case conversion, you could simply call STRING-EQUAL which ignores case. Thus:
Code: Select all
(STRING-EQUAL "foo" "FOO")
     => T


In your case, you'd do

Code: Select all
(string-equal (symbol-name arg) "then")
Cheers, Dave
Slowly but surely the world is finding Lisp. http://www.findinglisp.com/blog/
findinglisp
 
Posts: 440
Joined: Sat Jun 28, 2008 7:49 am
Location: Austin, TX

Re: Using barewords not keywords in macros

Postby gugamilare » Fri Apr 17, 2009 11:27 pm

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.


All right, it looks like you are getting the hang of macros. Don't worry, these details confuse sometimes, specially in the beginning. :D

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:

Code: Select all
(equal (string-downcase (symbol-name arg)) "then")


you can just

Code: Select all
(eq arg :then)


Or you can even use case:

Code: Select all
(case arg
  (:then ...)
  (:else ...))
gugamilare
 
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil

Re: Using barewords not keywords in macros

Postby findinglisp » Mon Apr 20, 2009 1:00 pm

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:

Code: Select all
(equal (string-downcase (symbol-name arg)) "then")


you can just

Code: Select all
(eq arg :then)


Or you can even use case:

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.
Cheers, Dave
Slowly but surely the world is finding Lisp. http://www.findinglisp.com/blog/
findinglisp
 
Posts: 440
Joined: Sat Jun 28, 2008 7:49 am
Location: Austin, TX


Return to Common Lisp

Who is online

Users browsing this forum: joeish80829 and 1 guest

cron