鉴于我有一个形式的表达
'(map? %)
我如何将它转换成类似的东西
'#(map? %)
这样我最终可以将其扩展为类似
'(apply #(map? %) value)
我想我应该以某种方式使用宏,但不确定如何。
鉴于我有一个形式的表达
'(map? %)
我如何将它转换成类似的东西
'#(map? %)
这样我最终可以将其扩展为类似
'(apply #(map? %) value)
我想我应该以某种方式使用宏,但不确定如何。
调用读取器#
宏和读取器宏扩展发生在正常宏扩展发生之前。因此,要执行您提到的操作,您需要在宏中使用阅读器,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)
#(...)
是一个阅读器宏。我认为您不能使用阅读器宏生成表达式。例如'#(map? %)
会自动展开成(fn* [p1__352#] (map? p1__352#))
或类似的东西。
这是关于其他阅读器宏的一些相关讨论。
是否可以更改谓词的格式?如果它看起来像:
'([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 给出的其他解决方案的区别是: