Am 17.12.2008 um 18:21 schrieb David Nolen:
> You can have unresolved symbols within a macro with:
> ~'symbol
I don't think this is really an alternative.
>> (def x 5)
>> (sql col1 from table1 where col2 = ~x)
(sql `(~'select ~'col1 ~'from ~'table1 ~'where ~'col2 ~'= ~x))
>> (def *cmd* "/usr/bin/command")
>> (run (~*cmd* -option 1 -another argument foo bar))
(run `(~*cmd* ~'-option 1 ~'-another ~'argument ~'foo ~'bar))
Also list with quote is quite verbose:
(sql (list 'select 'col1 'from 'table1 'where 'col2 '= x))
This also doesn't compare in ease of use and elegance to the
Scheme version.
Sincerely
Meikel
I very much like the sound of this.
+1
--Chouser
SVN 1184 implements this.
Feedback welcome on its utility for macro writers.
Rich
Here's an example of one way to use it:
user=> (where (and (> i (- 3 1)) (< i ~(+ 3 1))))
"where i > 3 - 1 and i < 4"
user=> (let [my-name "'chouser'"] (where (and (> id 0) (= name ~my-name))))
"where id > 0 and name = 'chouser'"
This 'where' macro produces something that looks vaguely like a SQL
"where" clause. It accepts s-expressions to translate, but also
allows you to mark sub-expressions with ~ to indicate that they should
be evaluated as regular clojure expresions, and not translated
literally to SQL. If it were more than a toy example, it would use
prepareStatement or similar to get appropriate quoting of clojure
objects, rather than just stuffing them directly in the resulting
string.
Here's the code:
(defmacro where [e]
(let [f (fn f [e]
(if-not (list? e)
[(str e)]
(let [[p & r] e]
(if (= p `unquote)
r
(apply concat (interpose [(str " " p " ")]
(map f r)))))))]
(list* `str "where " (f e))))
--Chouser
Am 23.12.2008 um 17:08 schrieb Rich Hickey:
> SVN 1184 implements this.
>
> Feedback welcome on its utility for macro writers.
Many Thanks Rich!
Here is a half-baked quasiquote macro ripped out of the
syntax-quote reader:
(defmacro quasiquote
[form]
(let [unquote? (fn [f] (and (seq? f) (= (first f) `unquote)))
self-eval? (fn [f] (or (keyword? f)
(number? f)
(instance? Character f)
(string? f)))
flatten-map (fn [m] (reduce (fn [r e]
(-> r (conj (key e)) (conj (val
e))))
[] m))
qq (fn qq [form]
(cond
(self-eval? form) form
(unquote? form) (second form)
(symbol? form) (list 'quote form)
(vector? form) (vec (map qq form))
(map? form) (apply hash-map
(map qq (flatten-map
form)))
(set? form) (apply hash-set (map qq
form))
(seq? form) (list* `list (map qq form))
:else (list 'quote form)))]
(qq form)))
With some example application:
Gorilla=> (def abc 5)
#'user/abc
Gorilla=> (let [fgh 6] (quasiquote (+ ~abc ~(+ abc fgh) xyz)))
(+ 5 11 xyz)
Sincerely
Meikel
Am 16.01.2009 um 00:36 schrieb Jason Wolfe:
> I like this a lot. Any chance of getting the same treatment for
> unquote-splicing?
>
> user> '~x
> (clojure.core/unquote x)
> user> '~@x
> ; Exception: can't embed object in code
> ; Desired output: (clojure.core/unquote-splicing x)
That's a good idea. It would nicely complement the other
functions so far. Please find attached a patch.
1:1 user=> '~x
(clojure.core/unquote x)
1:2 user=> '~@x
(clojure.core/unquote-splicing x)
Sincerely
Meikel