I'm trying to create a function to create a new basewith another struct as a base, and as a start I attempted to make a macro that would create a new struct with the same fields as the old one. The macro I have which i thought should do this is below, but it is giving 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))))
Example of use:
(defstruct bintree :data :left :right)
(def a (struct bintree 3))
(prototype bintree a)
The desired output in this case would be
{:data 3 :left nil :right nil}
The link seth posted as a comment to your question contains the answer (the culprit is the way arguments to anonymous functions are handled); the following, using a gensym argument, should work:
(defmacro prototype [structure obj]
`(apply struct ~structure (map (fn [x#] (~obj x#)) (keys ~obj))))
Here's a fixed version:
(defmacro prototype [structure obj]
`(apply struct ~structure (map ~obj (keys ~obj))))
Why does this need to be a macro? A function works too:
(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 does the same thing as the one above:
(defn prototype [structure obj] obj)
If you want to create a new structure with additional keys&values, use assoc
.
You shouldn't 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 namespace-qualified symbol in its parameter list. That's the error you're getting. You should avoid this kind of special reader syntax in macros and use the long forms instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With