0

我有一个函数,它返回 seq 中存在值 v 的索引:

(defn indexes-of [v s]
  (map first (filter #(= v (last %)) (zipmap (range) s))))

我想做的是扩展它以将任意函数应用于存在测试。我的想法是使用多方法,但我不确定如何检测函数。我想做这个:

(defmulti indexes-of ???)
(defmethod indexes-of ??? [v s]  ;; v is a function
  (map first (filter v (zipmap (range) s))))
(defmethod indexes-of ??? [v s]  ;; v is not a function
  (indexes-of #(= v %) s))

多方法是走这里的路吗?如果是这样,我怎样才能完成我想做的事情?

4

3 回答 3

1
(defmulti indexes-of (fn [v _]
                       (if (fn? v)
                         :function
                         :value)))
(defmethod indexes-of :function
  [f coll]
  (keep-indexed (fn [i v] (when (f v) i)) coll))

(defmethod indexes-of :value
  [v coll]
  (indexes-of (partial = v) coll))
于 2013-10-25T15:52:27.513 回答
1

更简单,更通用的东西怎么样:

(defn index-matches [predicate s]
  (map first (filter (comp predicate second) (map vector (range) s))))

user> (index-matches even? (reverse (range 10)))
(1 3 5 7 9)
user> (index-matches #{3} [0 1 2 3 1 3 44 3 1 3])
(3 5 7 9)

感谢 lgrapenthin 的建议,这个函数现在对惰性输入也有效:

user> (take 1 (index-matches #{300000} (range)))
(300000)
于 2013-10-25T15:56:09.320 回答
1

如果你想使用多方法,它应该在 filter 函数上,它是根据existence test类型而变化的。

所以

(defmulti filter-test (fn [value element] 
                        (cond 
                         (fn? value) :function
                         :else :value)))

(defmethod filter-test :function
  [value element]
   (apply value [element]))

(defmethod filter-test :value
   [value element]
  (= value element))

(defn indexes-of [v s]
   (map first (filter #(filter-test v (last %)) (zipmap (range) s))))

考虑到 JVM 不支持开箱即用的一流函数或 lambda,因此没有“函数”数据类型可供调度,这就是fn?测试的原因。

尽管如此,在这种情况下,IMOpredicate提出的解决方案noisesmith是正确的方法。

于 2013-10-25T15:56:53.397 回答