Clojure 为什么宏扩展不打印defmacro的结果?

Clojure 为什么宏扩展不打印defmacro的结果?,clojure,Clojure,我是Clojure的新手,目前正在尝试使用defmacro和macroexpand调用一个简单的宏 (ns tutorial.core (:gen-class)) ; namespace (defn -main [& args] (defmacro Simple [] (println "Hello")) (macroexpand '(Simple)) ) 我错过了什么吗?程序运行似乎没有任何问题,但结果并没

我是Clojure的新手,目前正在尝试使用
defmacro
macroexpand
调用一个简单的宏

(ns tutorial.core
  (:gen-class)) ; namespace

(defn -main [& args]
    
      (defmacro Simple [] (println "Hello"))
      (macroexpand '(Simple))
    
    )
我错过了什么吗?程序运行似乎没有任何问题,但结果并没有如预期的那样

我希望结果打印为
Hello
,但此脚本不会产生任何输出结果。

前言: 关于(IMHO)的概述,请参见过去的问题


答复: 您不应该在
main
函数中定义宏。试试这个:

(ns demo.core)

(defmacro happy
  []
  `(println "I'm happy!"))   ; *** notice the backtick! ***

(defn -main [& args]
  (println :expanded (macroexpand '(happy)))
  (happy)
  )
启动repl:

~/expr/demo > lein repl

demo.core=> (macroexpand '(happy))
;=> (clojure.core/println "I'm happy!")
我们看到它是有效的。尝试从命令行运行:

~/expr/demo > lein run
:expanded (happy)   ;  <= ***** OOOPS!  *****
I'm happy!
解释是,语法引号将完全限定Var
happy
=>
demo.core/happy
(由于该语法引号,您可以在
happy
宏内部的
println
Var上看到相同的效果)。这允许宏扩展正常工作。与单个报价相比:

(defn -main [& args]
  (println :expanded (macroexpand '(demo.core/happy)))
  (happy))

~/expr/demo > lein run
:expanded (clojure.core/println I'm happy!)
I'm happy!
这种行为的原因是,在REPL中,我们从提示中看到我们在
demo.core
命名空间中,因此
happy
被解析为
demo.core/happy
。但是,当我们在运行时使用
时,请注意:

(defn -main [& args]
  (println *ns*)
  (println (ns-name *ns*)))
结果:

~/expr/demo > lein run
*ns*             => #object[clojure.lang.Namespace 0xb625b00 "user"]
(ns-name *ns*)   => user
我们看到
*ns*
被设置为
用户
名称空间,
happy
无法解析为Var
demo.core/happy
,除非我们手动或在代码中使用
语法引号
对其进行完全限定


你可以找到一份工作。一定要特别学习Clojure备忘单


对于宏,这本书也很好。

宏函数不会返回代码,但会立即打印。这是一种非常糟糕的风格,因为它会带来意想不到的后果

如果要使用此功能:

(defn hello [] (Simple))
创建函数时,它会打印“Hello”。插入函数的代码是
println
的结果,即
nil
,因此您创建了以下代码:

(defn hello [] nil)
然后,如果调用
hello
3次,则所有调用都不会进行任何打印,因为宏只生成
nil
。如果将宏更改为返回结构:

;; The quote that makes all the difference
(defmacro Simple [] '(println "Hello"))
在创建
hello
的过程中,if将不会打印任何内容,但扩展将是
(println“hello”)
,相同的功能
hello
将变成:

(defn hello [] (println "Hello"))
(defn hello [] (println "Hello"))