Re: Expanding symbols and expression in macros.

2011-07-13 Thread Ken Wesson
On Wed, Jul 13, 2011 at 10:33 AM, Andrea Tortorella  wrote:
> I'm not an expert in macros, and maybe this is a stupid question but i
> think there should be a general pattern for this.
>
> I' ve a function:
>
> (defn choose* [f & choices]
>  "Applies f to one of the choices"
> . .)
>
> And this macro:
>
> (defmacro choose [[c choices] & body]
>  `(choose* (fn [~c] ~@body) ~@choices))
>
> Now if i call it with a literal sequence:
>
> (choose [x [:a :b :c]]
>   (println x))
>
> it correctly expands to:
>
> (choose* (fn [x] (println x)) :a :b :c)
>
> but if i have:
>
> (def y [:a :b :c])
> (choose [x y]
>  (println x))
>
> it gives me an error: don't know how to create ISeq from symbol.
>
> with an expression:
>
> (choose [x (vec 2 3 4)]
>   (println x))
>
> it expands to:
>
> (choose* (fn [x] (println x)) vec 2 3 4)
>
> I knew it could not be that simple, and i also understand why i get
> theese expansions, but i don't get how to solve it.
> So what's the pattern for something like this, where you want to
> evaluate a symbol or an expression before expansion?
>
> Andrea

Macros splice in an unevaluated expression.

You'll get what you want if you change the definition of choose* to:

(defn choose* [f choices]
  "Applies f to one of the choices"
  . .)

so it takes a function and a sequence argument, rather than a function
and a variable number of element arguments, and of choose to:

(defmacro choose [[c choices] & body]
  `(choose* (fn [~c] ~@body) ~choices))

so it doesn't splice choices. Your last example

(choose [x (vec 2 3 4)]
  (println x))

should now expand to:

(choose* (fn [x] (println x)) (vec 2 3 4))

which means the new choose* will run with choices bound to the vector
[2 3 4] as you desired.

-- 
Protege: What is this seething mass of parentheses?!
Master: Your father's Lisp REPL. This is the language of a true
hacker. Not as clumsy or random as C++; a language for a more
civilized age.

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


Re: Expanding symbols and expression in macros.

2011-07-13 Thread Luc Prefontaine
(defmacro choose [[c choices] & body]
  `(choose* (fn [~c] ~@body) ~choices)) <--- not ~@, just ~

~@ expects a sequence result
In your first example, [:a :b :c] is a sequence but in the second example, y is 
not.

body is a sequence (& body), using ~@ there is ok there.

Luc P.

On Wed, 13 Jul 2011 07:33:57 -0700 (PDT)
Andrea Tortorella  wrote:

> I'm not an expert in macros, and maybe this is a stupid question but i
> think there should be a general pattern for this.
> 
> I' ve a function:
> 
> (defn choose* [f & choices]
>   "Applies f to one of the choices"
> . .)
> 
> And this macro:
> 
> (defmacro choose [[c choices] & body]
>  `(choose* (fn [~c] ~@body) ~@choices))
> 
> Now if i call it with a literal sequence:
> 
> (choose [x [:a :b :c]]
>(println x))
> 
> it correctly expands to:
> 
> (choose* (fn [x] (println x)) :a :b :c)
> 
> but if i have:
> 
> (def y [:a :b :c])
> (choose [x y]
>   (println x))
> 
> it gives me an error: don't know how to create ISeq from symbol.
> 
> with an expression:
> 
> (choose [x (vec 2 3 4)]
>(println x))
> 
> it expands to:
> 
> (choose* (fn [x] (println x)) vec 2 3 4)
> 
> I knew it could not be that simple, and i also understand why i get
> theese expansions, but i don't get how to solve it.
> So what's the pattern for something like this, where you want to
> evaluate a symbol or an expression before expansion?
> 
> Andrea
> 



-- 
Luc P.


The rabid Muppet

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