具有可选标志的Clojure参数

时间:2009-06-25 21:40:54

标签: clojure parameters keyword

将关键字作为可选标志实现到函数的最佳方法是什么? 我想进行函数调用,例如:

(myfunction 5)
(myfunction 6 :do-this)
(myfunction 3 :go-here)
(myfunction 2 :do-this :do-that)

使用defn,我可以定义一个函数,例如:

(defn myfunction [value & flags] ... )

flags成为一个列表。我可以编写自己的函数来搜索列表,但是这样的函数不包含在核心库中,所以我认为它不是惯用的。

我现在正在使用的是:

(defn flag-set? [list flag] (not (empty? (filter #(= flag %) list))))
(defn flag-add [list flag] (cons flag list))
(defn flag-remove [list flag] (filter #(not= flag %) list))

4 个答案:

答案 0 :(得分:9)

列表(以及向量和地图)不是基于值的查找的数据结构的良好选择(将是线性时间),这就是为什么clojure.core没有这样的函数。

集合确实通过“contains?”提供快速的基于值的查找,那么如何

(defn foo [value & flags]
  (let [flags (set flags)]
    (if (contains? flags :add-one)
      (inc value)
      value)))

如果没有多个标志,您可以使用这样的解构:

(defn foo [value & [flag]] …)

答案 1 :(得分:5)

clojure.contrib.def包含defnk - 宏,这使得使用关键字参数定义函数更加容易。

答案 2 :(得分:1)

您可以对destructuring可选参数使用哈希映射绑定,如下所示:

(defn myfunction 
  [value & {:keys [go-there do-this do-that times] :or {times 1}}]
  {:pre [(integer? times) (< 0 times)]}
  (println "Saw a" value)
  (when go-there
    (dotimes [n times]
      (when do-this (println "Did THIS with" value))
      (when do-that (println "Did THAT with" value)))))

上述功能可以通过以下方式调用:

(myfunction "foo" :go-there true :do-this true :do-that false :times 5)

请注意,您可以使用:or {times 1}子句为键定义默认值。由于默认值,以下函数调用仅循环一次:

(myfunction "foo" :go-there true :do-this true :do-that false)

此外,Clojure的precondition expressions允许方便地测试参数,这也适用于结构化键的值,因为它可以在参数后面的{:pre [...]}表达式中看到绑定。由于前置条件检查,以下调用将失败:

(myfunction "foo" :go-there true :do-this true :do-that false :times -1)

答案 3 :(得分:0)

严格来说,这不是最有效的写作方式,但很明显

(defn myfunction [value & flags] 
  (cond (contains? (set flags) :a) 1
        (contains? (set flags) :b) 2)

将因子(设置标志)提高效率可能更有效。