Macro help

5 views
Skip to first unread message

Miki

unread,
Nov 8, 2010, 10:02:31 AM11/8/10
to Clojure
Greetings,

I need some help with the 1'st macro I'm writing.
I have many tests in the format

(deftest user-test
(let [session (test-session :authorization)]
(dispatcher "USER bugs" session)
(is (= (:user @session) "bugs"))
(is (= (get-one session) "+OK Hello bugs\n"))))

I've tried writing

(defmacro def-dispatcher-test [test-name state command & body]
`(deftest ~test-name
(let [session (test-session ~state)]
(dispatcher ~command session)
~@body)))

(def-dispatcher-test user-test :authorization "USER bugs"
(is (= (:user @session) "bugs"))
(is (= (get-one session) "+OK Hello bugs\n")))


But I get the following error;

Caused by: java.lang.Exception: Can't let qualified name: pop32imap-
test/session


I probably need to add some magic to the session expansion, but can't
figure out what.

Thanks,
--
Miki

Sunil S Nandihalli

unread,
Nov 8, 2010, 10:10:50 AM11/8/10
to clo...@googlegroups.com
use session# instead of session .. I think that should work.. try it..

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Sunil S Nandihalli

unread,
Nov 8, 2010, 10:12:19 AM11/8/10
to clo...@googlegroups.com
Hi Miki,
 Just to elaborate on what I said before, session# creates a new symbol using gensym with a prefix session. It avoids accidental variable capture.
Sunil.

Alan

unread,
Nov 8, 2010, 11:56:05 AM11/8/10
to Clojure
This. Macros, unless you do some gymnastics, always generate fully-
qualified names, which is a Good Thing. You can't bind qnames, in let
or function arguments or anywhere else. But clojure provides you with
a very useful var# syntax: this creates a new symbol which is
guaranteed to be unique, and lets you refer to it by that name
throughout the macro expansion. Here's a basic example:

(defmacro square [x]
`(let [val# ~x]
(* val# val#)))

(macroexpand '(square 3))

==> (let* [val__4209__auto__ 3]
(clojure.core/* val__4209__auto__ val__4209__auto__))


On Nov 8, 7:10 am, Sunil S Nandihalli <sunil.nandiha...@gmail.com>
wrote:
> use session# instead of session .. I think that should work.. try it..
>
> > clojure+u...@googlegroups.com<clojure%2Bunsu...@googlegroups.com>

Leif Walsh

unread,
Nov 8, 2010, 11:57:36 AM11/8/10
to clo...@googlegroups.com
Miki:

This is what Sunil is talking about:
http://en.wikipedia.org/wiki/Common_Lisp#Variable_capture_and_shadowing

The "symbol#" string is a part of how syntax-quote works. Read
http://clojure.org/reader#The Reader--Macro characters

On Mon, Nov 8, 2010 at 10:12 AM, Sunil S Nandihalli

--
Cheers,
Leif

Miki

unread,
Nov 8, 2010, 12:59:55 PM11/8/10
to Clojure
Hello Sunil,

>  Just to elaborate on what I said before, session# creates a new symbol
> using gensym with a prefix session. It avoids accidental variable capture.
Thanks for the quick reply. However I *do* want the symbol name to be
"session" since the
code in "body" uses it.

All the best,
--
Miki

Miki

unread,
Nov 8, 2010, 1:01:09 PM11/8/10
to Clojure
As in the below (which doesn't work).


(defmacro def-dispatcher-test [test-name state command & body]
`(deftest ~test-name
(let [session (test-session ~state)]
(dispatcher ~command session)
~@body)))

(def-dispatcher-test user-test :authorization "USER bugs"
(is (= (:user @session) "bugs"))
(is (= (get-one session) "+OK Hello bugs\n")))


Laurent PETIT

unread,
Nov 8, 2010, 2:01:00 PM11/8/10
to clo...@googlegroups.com
Hi,

session will be fully qualified. this is the default behavior.
If you really want it, then you can treat it as the result of the
unquoting of a value which resolves to a symbol.

So you'll use ~ to say you want the value of .... (quote session)
(quote session returns the symbol session when evaluated).

that is, use ~'session instead of just session.

HTH,

--
Laurent

2010/11/8 Miki <miki....@gmail.com>:

Ken Wesson

unread,
Nov 8, 2010, 2:16:52 PM11/8/10
to clo...@googlegroups.com
On Mon, Nov 8, 2010 at 2:01 PM, Laurent PETIT <lauren...@gmail.com> wrote:
> Hi,
>
> session will be fully qualified. this is the default behavior.
> If you really want it, then you can treat it as the result of the
> unquoting of a value which resolves to a symbol.
>
> So you'll use ~ to say you want the value of .... (quote session)
> (quote session returns the symbol session when evaluated).
>
> that is, use ~'session instead of just session.

Ugh.

What you really want in this case is a binding. Try this:


(defmacro def-dispatcher-test [test-name state command session-sym & body]
`(deftest ~test-name
(let [~session-sym (test-session ~state)]
(dispatcher ~command ~session-sym)
~@body)))

(def-dispatcher-test user-test :authorization "USER bugs" session


(is (= (:user @session) "bugs"))
(is (= (get-one session) "+OK Hello bugs\n")))


The added parameter just before the body specifies a name to bind the
session object to; this name can then be used in the body.

Miki

unread,
Nov 8, 2010, 2:36:32 PM11/8/10
to Clojure
Great, that did it. Thanks.

On Nov 8, 11:01 am, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> Hi,
>
> session will be fully qualified. this is the default behavior.
> If you really want it, then you can treat it as the result of the
> unquoting of a value which resolves to a symbol.
>
> So you'll use ~ to say you want the value of .... (quote session)
> (quote session returns the symbol session when evaluated).
>
> that is, use ~'session instead of just session.
>
> HTH,
>
> --
> Laurent
>
> 2010/11/8 Miki <miki.teb...@gmail.com>:

Miki

unread,
Nov 8, 2010, 2:38:29 PM11/8/10
to Clojure
>> that is, use ~'session instead of just session.
> What you really want in this case is a binding. Try this:
> ...
> The added parameter just before the body specifies a name to bind the
> session object to; this name can then be used in the body.
This is good a well, but I prefer to dark magic suggested by Laurent :)

Alan

unread,
Nov 8, 2010, 3:23:38 PM11/8/10
to Clojure
Yes, those are the two choices. Ken's suggestion is the cleanest, and
you definitely should do that in cases where it's not burdensome.
Here, where it's a macro for private testing, and you are certain not
to forget that it's magically binding session for you, then go ahead
and use Laurent's suggestion to create bindings.

Laurent PETIT

unread,
Nov 8, 2010, 3:32:45 PM11/8/10
to clo...@googlegroups.com


2010/11/8 Alan <al...@malloys.org>

Yes, those are the two choices. Ken's suggestion is the cleanest, and
you definitely should do that in cases where it's not burdensome.
Here, where it's a macro for private testing, and you are certain not
to forget that it's magically binding session for you, then go ahead
and use Laurent's suggestion to create bindings.

Ay, it was not a suggestion, just a specific answer to the specific question  :-)
 

On Nov 8, 11:38 am, Miki <miki.teb...@gmail.com> wrote:
> >> that is, use ~'session instead of just session.
> > What you really want in this case is a binding. Try this:
> > ...
> > The added parameter just before the body specifies a name to bind the
> > session object to; this name can then be used in the body.
>
> This is good a well, but I prefer to dark magic suggested by Laurent :)

Alan

unread,
Nov 8, 2010, 8:30:50 PM11/8/10
to Clojure
Yeah, I know you wouldn't make such a dreadful recommendation without
prompting. I just want to make sure *he* knows that this is considered
a little smelly: Clojure gives you the power to do stuff like this,
and it's appropriate to use it sometimes, but you should be careful -
it's hard for a reason.

On Nov 8, 12:32 pm, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> 2010/11/8 Alan <a...@malloys.org>
> > clojure+u...@googlegroups.com<clojure%2Bunsu...@googlegroups.com>

Miki

unread,
Nov 8, 2010, 11:23:03 PM11/8/10
to Clojure
> I just want to make sure *he* knows that this is considered
> a little smelly: Clojure gives you the power to do stuff like this,
> and it's appropriate to use it sometimes, but you should be careful -
> it's hard for a reason.
I know it smells, and regularly I won't use such a thing (didn't like
these things when read about them in "On Lisp" as well).
However I think in the current situation it's the best solution.

Thanks again.
Reply all
Reply to author
Forward
0 new messages