鉴于我有一个表格
'(map? %)
如何将其转换为
之类的内容'#(map? %)
这样我最终可以将其扩展为类似
的内容'(apply #(map? %) value)
我想我应该以某种方式使用宏,但我不确定如何。
答案 0 :(得分:6)
#
调用读取器宏和读取器宏扩展在正常宏扩展发生之前发生。因此,要执行您提到的内容,您需要使用read-string
在宏中浏览阅读器,如下所示。
(defmacro pred [p v]
(let [s# (str \# (last p))]
`(apply ~(read-string s#) ~v)))
user=> (pred '(map? %) [{}])
true
user=> (pred '(map? %) [[]])
false
如果数据,即谓词表达式在运行时可用,那么您需要使用一个函数(比宏更灵活)。
(defn pred [p v]
(let [s (read-string (str \# p))]
(eval `(apply ~s ~v))))
user=> (map #(pred % [12]) ['(map? %)'(even? %)])
(false true)
答案 1 :(得分:3)
#(...)
是一个读者宏。我认为你不能用reader宏生成表达式。例如,'#(map? %)
会自动扩展为(fn* [p1__352#] (map? p1__352#))
或类似内容。
这是其他阅读器宏的relevant discussion。
是否可以更改谓词的格式?如果它看起来像:
'([arg1] (map? arg1))
然后用它来形成一个函数是微不足道的:
(cons 'fn '([arg1] (map? arg1)))
(def pred (eval (cons 'fn '([p](map? p)))))
#'predicate.core/pred
(pred {})
true
(pred 10)
false
现在请不要因为我接下来要发布的内容而恨我。我写了一个过度简化的函数阅读器宏版本:
(defn get-args [p]
(filter #(.matches (str %) "%\\d*")
(flatten p)))
(defn gen-args [p]
(into []
(into (sorted-set)
(get-args p))))
(defmacro simulate-reader [p]
(let [arglist (gen-args p)
p (if (= (str (first p)) "quote")
(second p)
p)]
(list 'fn (gen-args p) p)))
使用它非常简单:
((simulate-reader '(map? %)) {}) ; -> true
; or without quote
((simulate-reader (map? %)) {})
; This also works:
((simulate-reader '(+ %1 %2)) 10 5) ; -> 15
与@Ankur给出的其他解决方案的区别在于: