更新时间:2022-12-17 16:01:33
虽然不能将map
与宏一起使用,但是可以编写第二个宏来执行此功能.反过来,这可能需要编写第三个宏,依此类推,这是
While you can't use map
with a macro, you could write a second macro to perform this function. This may, in turn, require writing a third macro, etc, which is the origin of the phrase "Macros All the Way Down" as described in Clojure for the Brave and True and other places.
使用Clojure的intern
函数在在此处回答了.我们的问题与该问题略有不同,因为在这里我们以两种不同的方式使用intern
:
A similar question was answered here by using Clojure's intern
function. Our problem is a little different than that question, since here we use intern
in two different ways:
def
或defn
var-get
def
or defn
var-get
使用intern
允许我们编写以下代码,以在不使用宏的情况下自动生成on-*
函数:
Using intern
allows us to write the following code to automatically generate the on-*
functions without using macros:
(defn generate-onstar-f
[event-kw]
(let [
event-str (name event-kw)
do-fn-sym (symbol (str "do-" event-str))
on-fn-sym (symbol (str "on-" event-str))
new-fn (fn on-fn-sym []
(let [the-var (intern 'tst.clj.core do-fn-sym) ; get the var the symbol 'do-fn-sym' points to
the-fn (var-get the-var) ] ; get the fn the var is pointing to
(the-fn))) ]
(intern 'tst.clj.core on-fn-sym new-fn) ; create a var 'on-fn-sym' pointing to 'new-fn'
(println "Created" on-fn-sym)))
(println \newline "*** generating functions ***")
(mapv generate-onstar-f [:foo :bar :baz]) ; creates and interns a functions: my-foo, my-bar, my-baz
(println \newline "Calling automatically generated on-* functions")
(on-foo)
(on-bar)
(on-baz)
有结果:
*** generating functions ***
Created on-foo
Created on-bar
Created on-baz
Calling automatically generated on-* functions
I foo'ed
I bar'ed
I baz'ed
因此,我们看到我们创建了函数on-foo
,on-bar
& on-baz
,依次称为全局do-foo
,do-bar
和& do-baz
功能.而且我们不需要使用宏!
So we see that we created the functions on-foo
, on-bar
& on-baz
which, in turn, call the global do-foo
, do-bar
, & do-baz
functions. And we didn't need to use macros!
在Clojure中,var有点像on-foo
这样的符号与其所指向的值(在此示例中为函数)之间的不可见中间人".有关更多信息,请参见相关文章:
In Clojure, the var is somewhat of an invisible "middle-man" between a symbol like on-foo
and the value it points to (a function in this example). For more information please see the relate post:
如前所述,可以使用宏调用另一个宏,从而避免了宏不能与map
之类的高阶函数(HOF)一起使用的问题.在这里,我们定义了一个新的宏run-macro
,以替换generate-onstar-f
不能使用的map
HOF:
As mentioned previously, one could use a macro to invoke another macro, side-stepping the problem that macros can't be used with higher-order-functions (HOF) like map
. Here we define a new macro run-macro
, to replace the map
HOF we can't use with generate-onstar-f
:
(defmacro generate-onstar-m
[event-kw]
(let [event-str (name event-kw)
do-fn-sym (symbol (str "do-" event-str))
on-fn-sym (symbol (str "on-" event-str "-m"))]
(println "Creating" on-fn-sym)
`(defn ~on-fn-sym []
(~do-fn-sym))))
(println \newline "Using Macro")
(generate-onstar-m :foo)
(on-foo-m)
(defmacro run-macro
"Run the specified macro once for each arg"
[root-macro args]
`(do
~@(forv [item args]
`(~root-macro ~item))))
(println \newline "Generating on-*-m functions using `run-macro`")
(run-macro generate-onstar-m [:foo :bar :baz])
(on-foo-m)
(on-bar-m)
(on-baz-m)
有结果:
Using Macro
Creating on-foo-m
I foo'ed
Generating on-*-m functions using `run-macro`
Creating on-foo-m
Creating on-bar-m
Creating on-baz-m
I foo'ed
I bar'ed
I baz'ed