如何将表达式转换为谓词?(Clojure)
假设我有一个表达式的形式如何将表达式转换为谓词?(Clojure),clojure,expression,predicate,Clojure,Expression,Predicate,假设我有一个表达式的形式 '(map? %) 如何将其转换为类似的内容 '#(map? %) 这样我就可以最终把它扩展成 '(apply #(map? %) value) 我想我应该以某种方式使用宏,但不确定如何使用。#(…)是一个读卡器宏。我认为不能用reader宏生成表达式。例如,”#(map?%)将自动展开为(fn*[p1_uuu352#](map?p1_352#))或类似内容 这里有一个关于其他阅读器的宏 是否可以更改谓词的格式?如果它看起来像: '([arg1] (map? ar
'(map? %)
如何将其转换为类似的内容
'#(map? %)
这样我就可以最终把它扩展成
'(apply #(map? %) value)
我想我应该以某种方式使用宏,但不确定如何使用。#(…)
是一个读卡器宏。我认为不能用reader宏生成表达式。例如,”#(map?%)
将自动展开为(fn*[p1_uuu352#](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
现在请不要因为我接下来要发布的内容而恨我。我编写了一个过于简化的function reader宏版本:
(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给出的其他解决方案的区别是:
#
调用读卡器宏,读卡器宏的扩展在正常宏扩展之前进行。因此,要执行您提到的操作,您需要使用read string
遍历宏中的读取器,如下所示
(defmacro pred [p v]
(let [s# (str \# (last p))]
`(apply ~(read-string s#) ~v)))
user=> (pred '(map? %) [{}])
true
user=> (pred '(map? %) [[]])
false
如果数据(即谓词表达式)在运行时可用,则需要使用函数(比宏更灵活)
您的意思是将
(map?%)
存储为数据,即作为带有两个符号的列表吗?是的,我确实在尝试在宏中执行此操作,我想我会引用所有内容来表示我想要的内容……但为什么要使用reader宏呢?为什么不直接使用fn
?可能是因为他希望输入谓词没有fn签名,并使用%1%2等作为参数名。这个问题非常具体,并没有提供可能导致更好的解决方案的整体情况好的一点,我没有看到,因为他的源数据包含对%
的引用,它似乎设计用于#(…)
。哇,非常有趣。我确信我遗漏了一些东西,因为我不知道如何使用正常的宏机制将#放置到位。我问这个问题的原因是因为我注意到prepost参数中的:post键是?在defn参数列表中,接受表达式向量。我很好奇表达式是如何计算的,因为它们被声明为表达式,而不是匿名函数。
(defn pred [p v]
(let [s (read-string (str \# p))]
(eval `(apply ~s ~v))))
user=> (map #(pred % [12]) ['(map? %)'(even? %)])
(false true)