我应该如何将String参数传递给clojure.core / apply

时间:2014-01-10 00:03:46

标签: clojure

我有以下代码:

  (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"] ...)

我不确定这是非常惯用的。有更好的解决方案吗?

2 个答案:

答案 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一起使用。