Using ?? in Clojurescript?

In my Clojure share, I have the following (which I shamelessly stole):

(defmacro hey-str [name] `(str "hey " ~name)) {:author "Laurent Petit (and others)" :doc "Functions/macros variants of the ones that can be found in clojure.core (note to other contrib members: feel free to add to this lib)"} (defmacro- defnilsafe [docstring non-safe-name nil-safe-name] `(defmacro ~nil-safe-name ~docstring {:arglists '([~'x ~'form] [~'x ~'form ~'& ~'forms])} ([x# form#] `(let [~'i# ~x#] (when-not (nil? ~'i#) (~'~non-safe-name ~'i# ~form#)))) ([x# form# & more#] `(~'~nil-safe-name (~'~nil-safe-name ~x# ~form#) ~@more #)))) (defnilsafe "Same as clojure.core/-> but returns nil as soon as the threaded value is nil itself (thus short-circuiting any pending computation). Examples : (-?> \"foo\" .toUpperCase (.substring 1)) returns \"OO\" (-?> nil .toUpperCase (.substring 1)) returns nil " -> -?>) (defnilsafe "Same as clojure.core/.. but returns nil as soon as the threaded value is nil itself (thus short-circuiting any pending computation). Examples : (.?. \"foo\" .toUpperCase (.substring 1)) returns \"OO\" (.?. nil .toUpperCase (.substring 1)) returns nil " .. .?.) (defnilsafe "Same as clojure.core/->> but returns nil as soon as the threaded value is nil itself (thus short-circuiting any pending computation). Examples : (-?>> (range 5) (map inc)) returns (1 2 3 4 5) (-?>> [] seq (map inc)) returns nil " ->> -?>>) 

In my Clojurescript code, I have the following (I: require-macros as c)

 (def a nil) (def b []) (def c [{:a 23}]) (js/alert (c/hey-str "Stephen")) ;; should display "hey Stephen" (js/alert (c/-?> a first :a)) ;; should display nil (js/alert (c/-?> b first :a)) ;; should display nil (js/alert (c/-?> c first :a)) ;; should display 23 

Unfortunately, when I compile, I get:

 WARNING: Use of undeclared Var webstack.client/-?> at line 56 cljs-src/webstack/client.cljs WARNING: Use of undeclared Var webstack.client/-?> at line 57 cljs-src/webstack/client.cljs WARNING: Use of undeclared Var webstack.client/-?> at line 58 cljs-src/webstack/client.cljs 

When I open javascript in the browser, I get a “hey Stephen” warning dialog box, but the widespread error “Not releasing TypeError: Unable to call the method“ from undefined ”occurs immediately after clicking“ ok ”on the warning“ hey Stephen. ”Of course, looking at generated javascript code, my js / alert became:

 alert([cljs.core.str("hey "), cljs.core.str("Stephen")].join("")); alert(webstack.client.__QMARK__GT_.call(null, webstack.client.__QMARK__GT_.call(null, webstack.client.a, cljs.core.first), "\ufdd0'a")); alert(webstack.client.__QMARK__GT_.call(null, webstack.client.__QMARK__GT_.call(null, webstack.client.b, cljs.core.first), "\ufdd0'a")); alert(webstack.client.__QMARK__GT_.call(null, webstack.client.__QMARK__GT_.call(null, webstack.client.c, cljs.core.first), "\ufdd0'a")) 

It's so clear that I can use macros, but something about how macros are written -? > (and related), causes them not to compile. What do I need to do to use macros -?> .?. and `-? →?

+4
source share
3 answers

-? > works for me using clojure 1.5.1 and cljsbuild 0.3.0, but only if I use: use-macros instead of: require-macroros. When I use: require-macros clojurescript tries to resolve the macro as var in the local namespace, which is not true. I think you found a bug in clojurescript, why don't you report it?

 (ns test.test ;(:use-macros [test.nilsafe :only [hey-str -?>]]) ;uncomment and everything works! (:require-macros [test.nilsafe :as tn])) (def a nil) (def b []) (def c [{:a 23}]) (.log js/console (tn/hey-str "Stephen")) ;; should display "hey Stephen" (.log js/console (tn/-?> a first :a)) ;; should display nil (.log js/console (tn/-?> b first :a)) ;; should display nil (.log js/console (tn/-?> c first :a)) 

What makes me sure that this is a mistake is that uncommenting: use-macros will cause the file to compile correctly even if I do not remove tn / scope from the variables.

+2
source

-> Marco is simple.

 (defmacro -> "Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc." {:added "1.0"} [x & forms] (loop [xx, forms forms] (if forms (let [form (first forms) threaded (if (seq? form) (with-meta `(~(first form) ~x ~@ (next form)) (meta form)) (list form x))] (recur threaded (next forms))) x))) 

write nil safe, which should be simple (the example below is not tested), but you get the concept.

 (defmacro -?> [x & forms] (loop [xx, forms forms] (if (and forms (some? x)) ; check nil to exit eariler (let [form (first forms) threaded (if (seq? form) (with-meta `(~(first form) ~x ~@ (next form)) (meta form)) (list form x))] (recur threaded (next forms))) x))) 
0
source

Maybe creating a function, and not another macro from a macro, can help solve this problem:

 (defmacro defnilsafe [docstring non-safe-name nil-safe-name] `(defn ~nil-safe-name ~docstring ([x# form#] (let [i# x#] (when-not (nil? i#) (~non-safe-name i# form#)))) ([x# form# & more#] (apply ~nil-safe-name (~nil-safe-name x# form#) more#)))) 
-1
source

Source: https://habr.com/ru/post/1441410/


All Articles