Proper handling of a symbol in macros

Let's say I want to create a Clojure macro that does the following:

If x is a list calling the function "bar"
  return :foobar
else
  return x as a string

However barnot determined; rather, it is used only inside the macro, for example:

(foo (bar))
:foobar

(foo 1)
"1"

You can do something like this:

(defmacro foo [x] 
  (if (and (coll? x) (= (first x) 'bar)) 
      :foobar 
      (str x)))

This works great for the case (bar)as well as for literals. However, the characters do not work as intended, specifying instead the name of the character:

user=> (def y 2)
#'user/y
user=> (foo y)
"y"

One could call the function evalon xbefore passing it to str, but this causes a problem when using the function in let:

user=> (let [a 3 b (foo a)] b)
java.lang.UnsupportedOperationException: Can't eval locals (NO_SOURCE_FILE:89)

Presumably the problem is with the resolution of the character, so maybe we will try to do something with a syntax quote:

(defmacro foo [x] 
  `(if (and (coll? '~x) (= (first '~x) '~'bar)) 
    :foobar 
    (str ~x)))

(foo (bar)), else (clojure.core/str (bar)), , bar . eval:

(defmacro foo [x] 
  `(if (and (coll? '~x) (= (first '~x) '~'bar)) 
    :foobar 
    (eval '(str ~x))))

let:

user=> (let [a 1 b (foo a)] b)
java.lang.Exception: Unable to resolve symbol: a in this context (NO_SOURCE_FILE:153)

. , . , :

  • let
  • (bar)

P.S. - , , DSL Yahoo YQL, , (select (table :t) ...), , .

+5
1

, .

(defmacro foo [x]
  (if (and (coll? x) (= (first x) 'bar))
    :foobar
    `(str ~x)))
+4

All Articles