(defmacro test-it [sym addend & body] `(let [~sym (+ ~addend 1)] ~@body))

would be the usual preferred Clojure way to handle this sort of situation,
but anaphoric is also an option. You can also make macros expand to a def
in the caller's namespace this way -- it's how defn works: (defmacro defn
[name .........] `(def ~name .........)). But you should only be interning
symbols if they make sense to add to the namespace.



On Mon, Jul 1, 2013 at 11:30 AM, Baishampayan Ghose <b.gh...@gmail.com>wrote:

> +1 totally agree. Eg. clojure.core/with-open
>
> Sent from phone. Please excuse brevity.
> On 1 Jul 2013 20:58, "Gary Trakhman" <gary.trakh...@gmail.com> wrote:
>
>> Whenever I make a macro like this, I pass the symbol to be captured as an
>> argument to the macro.  Any collisions would be more explicit and less
>> surprising.
>>
>>
>> On Mon, Jul 1, 2013 at 11:21 AM, Baishampayan Ghose <b.gh...@gmail.com>wrote:
>>
>>> Hi,
>>>
>>> What you need is called an anaphoric macro (via symbol capture).
>>> Clojure makes it hard to do a symbol capture in macros since it
>>> qualifies all symbols automatically unless you use the auto gensym
>>> feature. This is done for hygiene purposes and to avoid any unintended
>>> side-effects.
>>>
>>> However indeed, it's possible to create such a macro in Clojure.
>>>
>>> Behold -
>>>
>>> (defmacro test-it [addend & body] `(let [~'foo (+ ~addend 1)] ~@body))
>>> ;; notice the ~' in front of foo.
>>>
>>> (macroexpand-1 '(test-it 1 (println foo)))
>>> ;=> (clojure.core/let [foo (clojure.core/+ 1 1)] (println foo))
>>>
>>> Please apply caution before using this feature; document the symbol to
>>> be captured sufficiently.
>>>
>>> Hope that helps.
>>>
>>> Regards,
>>> BG
>>>
>>> On Mon, Jul 1, 2013 at 7:44 PM, Sean Johnson <belu...@acm.org> wrote:
>>> > Hello,
>>> >
>>> > If a macro calculates something and wants to make that result
>>> available to
>>> > the body, what's the right way to do that? So far I've tried these ways
>>> > which don't work (this is not really my macro, it's just a simplified
>>> > example to demonstrate the issue):
>>> >
>>> > 1) lexical scope doesn't work, the symbol gets qualified
>>> >
>>> > (defmacro test-it [addend & body] `(let [foo (+ ~addend 1)] ~@body))
>>> >
>>> > => (test-it 3 (println foo))
>>> > CompilerException java.lang.RuntimeException: Can't let qualified name:
>>> > fcms.app/foo, compiling:(NO_SOURCE_PATH:1:1)
>>> >
>>> > => (macroexpand '(test-it 3 (println foo)))
>>> > (let* [fcms.app/foo (clojure.core/+ 3 1)] (println foo))
>>> >
>>> >
>>> > 2) autogen'ed lexical scope doesn't work, the body doesn't know what
>>> the
>>> > autogen'ed symbol will be called
>>> >
>>> > (defmacro test-it [addend & body] `(let [foo# (+ ~addend 1)] ~@body))
>>> >
>>> > => (test-it 1 (println foo))
>>> > CompilerException java.lang.RuntimeException: Unable to resolve
>>> symbol: foo
>>> > in this context, compiling:(NO_SOURCE_PATH:1:12)
>>> >
>>> > => (macroexpand '(test-it 3 (println foo)))
>>> > (let* [foo__5755__auto__ (clojure.core/+ 3 1)] (println foo))
>>> >
>>> >
>>> > 3) an interned var partially works, if the macro and its use are all
>>> in one
>>> > namespace, but not if not, it fails to intern the var
>>> >
>>> > (defmacro test-it [addend & body] `(do (def foo (+ ~addend 1)) ~@body))
>>> >
>>> > => (test-it 3 (println foo))
>>> > 4
>>> > nil
>>> >
>>> > => (macroexpand '(test-it 3 (println foo)))
>>> > (do (def fcms.app/foo (clojure.core/+ 3 1)) (println foo))
>>> >
>>> > => (ns test)
>>> > nil
>>> > test=> (fcms.app/test-it 3 (println foo))
>>> > CompilerException java.lang.RuntimeException: Can't create defs
>>> outside of
>>> > current ns, compiling:(NO_SOURCE_PATH:1:1)
>>> >
>>> >
>>> > I don't think my scenario is too unusual, but so far I haven't been
>>> able to
>>> > find anything about how to best do this.
>>> >
>>> > It case it helps, the real macro is with-collection and it takes a
>>> > collection name, does a lookup and some validation in a DB, then needs
>>> to
>>> > share the collection's id with the body.
>>> >
>>> > Cheers,
>>> > Sean
>>> >
>>> >
>>> >
>>> > --
>>> > --
>>> > You received this message because you are subscribed to the Google
>>> > Groups "Clojure" group.
>>> > To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
>>> > For more options, visit this group at
>>> > http://groups.google.com/group/clojure?hl=en
>>> > ---
>>> > You received this message because you are subscribed to the Google
>>> Groups
>>> > "Clojure" group.
>>> > To unsubscribe from this group and stop receiving emails from it, send
>>> an
>>> > email to clojure+unsubscr...@googlegroups.com.
>>> > For more options, visit https://groups.google.com/groups/opt_out.
>>> >
>>> >
>>>
>>>
>>>
>>> --
>>> Baishampayan Ghose
>>> b.ghose at gmail.com
>>>
>>> --
>>> --
>>> You received this message because you are subscribed to the Google
>>> Groups "Clojure" group.
>>> To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
>>> For more options, visit this group at
>>> http://groups.google.com/group/clojure?hl=en
>>> ---
>>> You received this message because you are subscribed to the Google
>>> Groups "Clojure" group.
>>> To unsubscribe from this group and stop receiving emails from it, send
>>> an email to clojure+unsubscr...@googlegroups.com.
>>> For more options, visit https://groups.google.com/groups/opt_out.
>>>
>>>
>>>
>>  --
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "Clojure" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to clojure+unsubscr...@googlegroups.com.
>> For more options, visit https://groups.google.com/groups/opt_out.
>>
>>
>>
>  --
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
>

-- 
-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to