4

私のClojure共有ソースには、次のものがあります(恥知らずに盗みました):

(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
   "
  ->> -?>>)

私のClojurescriptコードには次のものがあります(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

残念ながら、コンパイルすると、次のようになります。

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

ブラウザーで JavaScript を開くと、"hey Stephen" アラート ダイアログが表示されますが、"hey Stephen" で "ok" を押した直後に、"Uncaught TypeError: Cannot call method 'call' of undefined" エラーが表示されます。アラート。案の定、生成された JavaScript コードを見ると、私の js/alert は次のようになりました。

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

明らかに、私はマクロを使用できますが、 -?> (および関連する) マクロの記述方法に関する何かが原因でコンパイルに失敗します。-?> .?.これらのマクロと `-?>>' マクロを使用するには、どうすればよいですか?

4

3 に答える 3

2

-?> は、clojure 1.5.1 と cljsbuild 0.3.0 を使用して動作しますが、:require-macros の代わりに :use-macros を使用した場合のみです。:require-macros を使用すると、clojurescript はマクロをローカル名前空間の var として解決しようとしますが、これは正しくありません。clojurescript にバグを見つけたと思いますが、報告してみてはいかがでしょうか?

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

これがバグであると確信できるのは、変数から tn/ スコープを削除しなくても、:use-macro のコメントを外すと、ファイルが正しくコンパイルされることです。

于 2013-03-27T10:07:59.580 に答える
-1

マクロから別のマクロではなく関数を作成すると、この問題の解決に役立つ場合があります。

(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#))))
于 2012-10-23T16:32:59.793 に答える