15

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

(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

5 回答 5

9

对于基于值的查找(将是线性时间),列表(以及向量和映射)不是一个好的数据结构选择,这就是为什么 clojure.core 没有这样的功能。

集合确实通过“包含?”提供基于值的快速查找,那么怎么样

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

如果不会有多个标志,您可以像这样使用解构:

(defn foo [value & [flag]] …)
于 2009-06-25T22:36:42.830 回答
5

clojure.contrib.def包括defnk-macro,它使使用关键字参数定义函数更容易。

于 2009-06-26T09:05:52.573 回答
1

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

(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 的前置条件表达式允许方便地测试参数,这也适用于解构键的值,因为它可以在{:pre [...]}参数绑定之后的表达式中看到。由于前提条件检查,以下调用将失败:

(myfunction "foo" :go-there true :do-this true :do-that false :times -1)
于 2014-05-13T19:41:25.443 回答
0

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

(defn myfunction [值 & 标志]
  (条件(包含?(设置标志):a)1
        (包含?(设置标志):b)2)

考虑(设置标志)可能更有效。

于 2009-06-25T22:34:23.773 回答
0

将其余参数列表转换为仅用于检查成员资格的集合可能被认为是笨拙的。不过,为此目的使用some静态集被认为是惯用的。所以你可以做这样的事情

(defn myfunction [value & flags]
  (if (some #{:do-this} flags)
    [value flags]))

(myfunction 123 :do-this)
-> [123 (:do-this)]

另一种方法是使用Clojure 1.2 中引入的关键字参数。例如

(defn myfunction [value & {:keys [do-this]}]
  (if do-this
    [value do-this]))

(myfunction 123 :do-this true)
-> [123 true]

这给调用者增加了“负担”来true为标志提供一个明确的值,但是函数签名可以说变得不那么模糊和自我记录(因为像这样的名字flags是相当抽象的)。所以我认为这是一个权衡。

于 2021-11-09T23:05:26.843 回答