简体   繁体   中英

Macro with a function definition including set! not working in Clojurescript

I'm trying to define a macro that should do the following:

  • Bind a 'variable' with an initial value
  • Create setter methods with a name based on the variable name

I have the following defined in a clojure file:

(defmacro defprop
  [prop-name init-value]
  `(do
    (def ~prop-name ~init-value)
    (def ~(symbol (str prop-name "-other")) ~init-value)
    (defn ~(symbol (str prop-name "-11")) [] (set! ~prop-name 11))
    (defn ~(symbol (str prop-name "-set")) [new-val] (set! ~prop-name new-val))))

When invoked from clojurescript like this (cmacros is the namespace alias):

(cmacros/defprop production 350)

I get the definition of 'production' and 'production-other' right, the function 'production-11' works (and sets to 11 the value of production), but the last one does not work. I get different errors in different browsers. Chrome says "Uncaught SyntaxError: Unexpected token .". Firefox "SyntaxError: missing ) after formal parameters".

The offending javascript code pointed out by Firefox looks like this:

cgamemini.core.production_set = (function
  cgamemini$core$production_set(cgamemini.macros.new_val) {
    return cgamemini.core.production = cgamemini.macros.new_val;
  }
);

Which seems to have all the parenthesis right, although I'm no js specialist. What's going wrong? Why is the -11 definition working but not the -set?

The problem is new-val . Clojure macro expansion doesn't understand syntax so it doesn't know that new-val is supposed to be an argument -- any bare symbols that occur in a macro expansion at automatically namespaced to the current namespace. That's why you see cgamemini$core$production_set(cgamemini.macros.new_val) in your output. What you want to do is use hygienic macro syntax to indicate that a fresh symbol should be created that is not namespaced, eg

`(defn ~(symbol (str prop-name "-set")) [new-val#] (set! ~prop-name new-val#))

An alternative is to inject your symbol:

`(defn ~(symbol (str prop-name "-set")) [~'new-val] (set! ~prop-name ~'new-val))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM