clojurescript 中的宏 - 未正确扩展
macros in clojurescript - does not expand properly
我在 clojure 中创建了一个宏
(ns macro-question.map)
(defmacro lookup [key] (list get (apply hash-map (range 1 5)) key))
在 clojure repl 中它按预期工作
$ clj
Clojure 1.9.0
user=> (require 'macro-question.map)
nil
user=> (macro-question.map/lookup 1)
2
所以我创建了一个像这样的 clojurescript 模块来尝试使用它:
(ns macro-question.core (:require-macros [macro-question.map]))
(defn lookup1 [] (macro-question.map/lookup 1))
当我在 repl 中尝试这样做时,我得到了这个
$ clj -m cljs.main --repl-env node
ClojureScript 1.10.520
cljs.user=> (require 'macro-question.core)
Execution error (ExceptionInfo) at cljs.compiler/fn (compiler.cljc:304).
failed compiling constant: clojure.core$get@3df1a1ac; clojure.core$get is not a valid ClojureScript constant.
同时回到 clojure,有一个线索可以解释为什么会这样
user=> (macroexpand '(macro-question.map/lookup 1))
(#object[clojure.core$get 0x101639ae "clojure.core$get@101639ae"] {1 2, 3 4} 1)
我可以创建以 '(
而非 (list
开头的宏。但是,我希望在构建时扩展地图。
这是怎么回事?我需要做什么才能得到类似以下内容:
user=> (macroexpand '(macro-question.map/lookup 1))
(get {1 2, 3 4} 1)
或者我应该怎么做才能在 clojurescript 中使用这个宏?
(list get (apply hash-map (range 1 5)) key)
创建一个列表,其中第一个位置是 var get
引用的函数对象。您真正想要 return 的是一个列表,其中 get
的完全限定 符号 作为第一个位置。将您的宏定义更改为
(defmacro lookup [key]
`(get ~(apply hash-map (range 1 5)) ~key))
(macroexpand '(lookup 1))
=> (clojure.core/get {1 2, 3 4} 1)
reader 的参考指南在这里很有帮助 https://clojure.org/reference/reader
你可以只输入 'get
!!
(ns macro-question.map)
(defmacro lookup [key] (list 'get (apply hash-map (range 1 5)) key))
(https://whosebug.com/posts/58985564 是关于为什么会发生的更好的答案,也是一种更好的方法。这只是展示了一个简单的解决方案,它只解决了眼前的问题,我在询问后立即意识到问题)
我在 clojure 中创建了一个宏
(ns macro-question.map)
(defmacro lookup [key] (list get (apply hash-map (range 1 5)) key))
在 clojure repl 中它按预期工作
$ clj
Clojure 1.9.0
user=> (require 'macro-question.map)
nil
user=> (macro-question.map/lookup 1)
2
所以我创建了一个像这样的 clojurescript 模块来尝试使用它:
(ns macro-question.core (:require-macros [macro-question.map]))
(defn lookup1 [] (macro-question.map/lookup 1))
当我在 repl 中尝试这样做时,我得到了这个
$ clj -m cljs.main --repl-env node
ClojureScript 1.10.520
cljs.user=> (require 'macro-question.core)
Execution error (ExceptionInfo) at cljs.compiler/fn (compiler.cljc:304).
failed compiling constant: clojure.core$get@3df1a1ac; clojure.core$get is not a valid ClojureScript constant.
同时回到 clojure,有一个线索可以解释为什么会这样
user=> (macroexpand '(macro-question.map/lookup 1))
(#object[clojure.core$get 0x101639ae "clojure.core$get@101639ae"] {1 2, 3 4} 1)
我可以创建以 '(
而非 (list
开头的宏。但是,我希望在构建时扩展地图。
这是怎么回事?我需要做什么才能得到类似以下内容:
user=> (macroexpand '(macro-question.map/lookup 1))
(get {1 2, 3 4} 1)
或者我应该怎么做才能在 clojurescript 中使用这个宏?
(list get (apply hash-map (range 1 5)) key)
创建一个列表,其中第一个位置是 var get
引用的函数对象。您真正想要 return 的是一个列表,其中 get
的完全限定 符号 作为第一个位置。将您的宏定义更改为
(defmacro lookup [key]
`(get ~(apply hash-map (range 1 5)) ~key))
(macroexpand '(lookup 1))
=> (clojure.core/get {1 2, 3 4} 1)
reader 的参考指南在这里很有帮助 https://clojure.org/reference/reader
你可以只输入 'get
!!
(ns macro-question.map)
(defmacro lookup [key] (list 'get (apply hash-map (range 1 5)) key))
(https://whosebug.com/posts/58985564 是关于为什么会发生的更好的答案,也是一种更好的方法。这只是展示了一个简单的解决方案,它只解决了眼前的问题,我在询问后立即意识到问题)