我有以下代码:
(condp apply "string argument"
predicate1? "Result1"
predicate2? "Result2"
predicate3? "Result3"
"Else")
目前,"string argument"
在传递给apply时被解释为seq,因此每个字符都成为谓词的参数:
(apply predicate1? \s \t \r \i \n ...)
一个简单的解决方案是将参数包装在一个向量中:
(condp apply ["string argument"] ...)
我不确定这是非常惯用的。有更好的解决方案吗?
答案 0 :(得分:2)
我认为没有比直接使用cond
更具惯用性的方法,将“字符串参数”绑定到符号并将其传递给每个谓词。对于阅读代码的人来说,其他所有内容都会让人感到困惑,并涉及额外的函数调用。
使用以下辅助宏可以实现额外的魔法:
(defmacro pcond
"Translates clauses [pred result-expr] to a cond form:
(cond
(pred expr) result-expr
...)
A single result-expr can follow the clauses, and it will be appended
to the cond form under a generated test expression that returns logical
true."
[expr & clauses]
(let [expr-sym (gensym "expr")
else-kw (keyword (gensym "else"))
step (fn [[pred-form clause-form]]
(if (= else-kw clause-form)
[else-kw pred-form]
[(list pred-form expr-sym) clause-form]))
body (->> clauses
(partition 2 2 [else-kw])
(mapcat step))]
`(let [~expr-sym ~expr]
(cond ~@body))))
你可以这样使用
(pcond "String argument"
predicate1 "Result1"
predicate2 "Result2"
"Else")
它直接扩展到cond:
(clojure.core/let [expr13755 "String argument"]
(clojure.core/cond
(predicate1 expr13755) "Result1"
(predicate2 expr13755) "Result2"
:else13756 "Else"))
答案 1 :(得分:1)
您可以使用匿名函数#(%1 %2)
来完成您要执行的操作。 IMO它比将condp
表达式包装在一个向量中更好,但无论哪种方式都有效,也不是真的很好。
(condp #(%1 %2) "string argument"
string? "string"
map? "map"
vector? "vector"
"something else")
;= Result1
编辑(从评论中复制)
我不是宏的专家,但我一遍又一遍地听到的是,如果一个函数会这样做你不应该写一个宏而condp
提供所有元素来使用Clojure的力量功能。不涉及宏并提高可读性的方法可以是定义函数(def apply-pred #(%1 %2))
并将其与condp
一起使用。