简体   繁体   English

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

[英]How should I pass a String argument to clojure.core/apply

I have the following piece of code: 我有以下代码:

  (condp apply "string argument"
    predicate1? "Result1"
    predicate2? "Result2"
    predicate3? "Result3"
                "Else")

Currently, "string argument" , when passed to apply gets interpreted as a seq, therefore each character becomes a parameter to the predicate: 目前, "string argument"在传递给apply时被解释为seq,因此每个字符都成为谓词的参数:

(apply predicate1? \s \t \r \i \n ...)

A simple solution would be to wrap the argument in a vector: 一个简单的解决方案是将参数包装在一个向量中:

(condp apply ["string argument"] ...)

I'm not sure this is very idiomatic. 我不确定这是非常惯用的。 Is there a better solution? 有更好的解决方案吗?

I don't think there is a more idiomatic way than using cond directly, binding "string argument" to a symbol and passing it to each predicate. 我认为没有比直接使用cond更具惯用性的方法,将“字符串参数”绑定到符号并将其传递给每个谓词。 Everything else looks confusing to people reading your code and involves extra function calls. 对于阅读代码的人来说,其他所有内容都会让人感到困惑

Extra magic could be achieved with the following helper macro: 使用以下辅助宏可以实现额外的魔力:

(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))))

You can use it so 你可以这样使用它

(pcond "String argument"
    predicate1 "Result1"
    predicate2 "Result2"
    "Else")

It macroexpands directly to cond: 它直接扩展到cond:

(clojure.core/let [expr13755 "String argument"] 
   (clojure.core/cond 
     (predicate1 expr13755) "Result1" 
     (predicate2 expr13755) "Result2" 
     :else13756 "Else"))

You can use the anonymous function #(%1 %2) for what you are trying to do. 您可以使用匿名函数#(%1 %2)来执行您要执行的操作。 IMO it's better than wrapping the condp expression in a vector, but either way works, neither is really straigthforward. IMO它比将condp表达式包装在一个向量中更好,但无论哪种方式都有效,也不是真正的直截了当。

(condp #(%1 %2) "string argument"
    string? "string"
    map?    "map"
    vector? "vector"
    "something else")

;= Result1

EDIT (copied from the comments) 编辑 (从评论中复制)

I'm no expert on macros, but what I've heard over and over is that you shouldn't write a macro if a function will do and condp provides all the elements to use the power of Clojure functions. 我不是宏的专家,但我一遍又一遍地听到的是,如果一个函数会做,你不应该写一个宏,而condp提供了使用Clojure函数的所有元素。 An approach that doesn't involve macros and improves readability could be defining a function (def apply-pred #(%1 %2)) and use it with condp . 一种不涉及宏并提高可读性的方法可以定义一个函数(def apply-pred #(%1 %2))并将其与condp一起condp

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM