设置,让,宏,坚果

时间:2012-10-20 02:28:02

标签: clojure macros

我正在尝试从html内容构建一个快速的toc。 (简而言之)

代码很简单:

(defn toc [content]
 (doseq [i (take 5 (iterate inc 1))] 
   (let [h  (str "h" i)]
    (println ($ content h)))))

其中内容是html内容, $ clojure-soup 所需的宏

虽然

($ content "h1")

有效,并返回所有标签的列表。

简单:

($ content (str "h" 1))

只是不会做任何我做的事。

我如何强制

(str "h" 1) 

要在调用宏之前正确评估吗?

解释原因的加分点:)

2 个答案:

答案 0 :(得分:3)

如果您暗示$是一个宏,那么这是不可能的:它根本不是宏的工作方式。宏需要在编译时扩展为某些内容,并且只能执行一次。您有运行时数据,如h的各种值,但在编译时无法使用它。对我而言,$听起来应该是一个功能。

答案 1 :(得分:2)

Amalloy回答问题why部分。对于making it work部分,您需要使用eval

取代($ content h)使用

(eval `($ content ~h))

为什么会出现这种情况的另一种解释是基于以下事实:宏在编译时执行了哪些操作以及它在运行时执行的操作(即它发出的代码)。以下是清除问题的例子。

(def user "ankur")
(defmacro do-at-compile [v] (if (string? v) `true `false))
(defmacro do-at-runtime [v] `(if (string? ~v) true false))

(do-at-compile "hello") ;; => true
(do-at-compile user) ;; => false, because macro does perform the check at compile time
(do-at-runtime "hello") ;; => true
(do-at-runtime user) ;; => true

$宏正在编译时对传递的第二个参数进行计算,因此在您的特定情况下它不起作用。