为什么 clojure 核心库不支持索引函数?

Why doesn't clojure core library support an index-of function?

最近,我开始学习 clojure 编程和一般的函数式编程。在解决一些基本的编程难题时,我注意到的一件事是向量没有索引函数,例如。核心功能没有反转 nth。我见过人们自己实现它或使用一些 java 替代实现。

我的问题不是是否有解决方法(但如果您知道一个特别优雅的解决方法,请分享),因为我知道有。我想知道的是:为什么会这样,例如。为什么 clojure 开发人员决定不实施看似如此基本的操作。在 clojure 中以某种方式在向量中进行位置查找是不是惯用的,并且理想情况下会以其他方式完成吗?怎么样?

以相反的顺序回答两个问题:

"Workaround":clojure 中的 vector 实现了 java.util.List,因此 java 工作简单(足够优雅,imo)

(.indexOf [1 2 3] 2)
1

此外,字符串可以利用clojure.string/index-of

为什么不在clojure.core中:这相当于一个问题"why there's no [a polymorphic fn] for various collection types",在这里回答:https://clojure.org/guides/faq#conj and here https://gist.github.com/reborg/dc8b0c96c397a56668905e2767fd697f#why-clojure-doesnt-have-a-generic-insert-lookup-append-that-works-the-same-on-all-collections

一个标准的 Clojure 函数,它几乎可以满足问题的要求。

如果我们查看 the skeleton source,我们需要做的是反转序列,例如...

(def ranks [2 3 4 5 6 7 8 9 10 :jack :queen :king :ace])

... 到地图(或其他函数)中,为我们提供 每个 值的索引:

{7 5, :king 11, 4 2, :queen 10, :ace 12, 6 4, 3 1, 2 0, :jack 9, 9 7, 5 3, 10 8, 8 6}

我们可以一劳永逸

几乎可以做到这一点的标准函数是clojure.set/map-invert

  • 但它适用于地图,不适用于序列。
  • 但它将它们视为成对序列。

因此,将向量(或其他序列)反转为索引函数的简单函数是...

(defn indexes-of [v]
  (->> v
       (map-indexed vector)
       (clojure.set/map-invert)))

例如,

   (indexes-of ranks)
=> {7 5, :king 11, 4 2, :queen 10, :ace 12, 6 4, 3 1, 2 0, :jack 9, 9 7, 5 3, 10 8, 8 6}

因此,那些说您的想法错误的人是正确的。 然而,在 Clojure 本身内执行这样的无域计算肯定更好,但是 Clojure 可以顺利地与它恰好在 运行 上的任何 VM 对接。

我们需要的是一个斗篷来覆盖矢量以使其成为地图:就像 rseq 将斗篷覆盖在矢量上一样,使它看起来像一个相反的序列。然后我们不需要假设 map-invert 将接受一个对序列。 (现在为了安全起见,我们可以为 into 对序列提供一个映射以提供给 map-invert)。