我正在尝试从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)
要在调用宏之前正确评估吗?
解释原因的加分点:)
答案 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
$
宏正在编译时对传递的第二个参数进行计算,因此在您的特定情况下它不起作用。