Clojure macro problem

I am trying to create a function to create a new basewith a different structure as a base, and as a start I tried to create a macro that would create a new structure with the same fields as the old one. The macro I thought should do it below, but it gives the following error:

java.lang.Exception: Can't use qualified name as parameter: user/p1__132 

Macro:

 (defmacro prototype [structure obj] `(apply struct ~structure (map #(~obj %) (keys ~obj)))) 

Usage example:

 (defstruct bintree :data :left :right) (def a (struct bintree 3)) (prototype bintree a) 

In this case, the desired result will be

 {:data 3 :left nil :right nil} 
+7
clojure
source share
3 answers

The seth link, posted as a comment on your question, contains the answer (the culprit is the way you handle the arguments of anonymous functions); the following, using the gensym argument, should work:

 (defmacro prototype [structure obj] `(apply struct ~structure (map (fn [x#] (~obj x#)) (keys ~obj)))) 
+8
source share

Here's the fixed version:

 (defmacro prototype [structure obj] `(apply struct ~structure (map ~obj (keys ~obj)))) 

Why should this be a macro? The function also works:

 (defn prototype [structure obj] (apply struct structure (map obj (keys obj)))) 

Why do you want to copy the structure? Structures are immutable, so copying them is not useful. This function performs the same function as above:

 (defn prototype [structure obj] obj) 

If you want to create a new structure with additional keys and values, use assoc .

+3
source share

You should not use #() inside a macro.

  user> (macroexpand-1 `(foo # (bar%) baz))
 (user / foo (fn * [user / p1__2047] (user / bar user / p1__2047)) user / baz) 

Not that the fn* form has a character with a namespace name in its parameter list. This is the error you are getting. You should avoid such special reader syntax in macros and use long forms.

+2
source share

All Articles