Types Clojure中具有不可变数据的向量与列表

Types Clojure中具有不可变数据的向量与列表,types,clojure,functional-programming,containers,Types,Clojure,Functional Programming,Containers,我已经编写了两次相同的函数,分别使用列表和向量。函数查找一个元素并返回集合中的下一个元素,如果找到的元素位于末尾,则将其换行nil 列表版本 (def syms'(\\v)) (定义下一个元素-[coll元素] (循环[coll rest coll] (续) (空?coll rest)无 (=(第一列)元素)(第n列第1列(第一列)) :else(重复出现(rest coll rest(()))) (defn向左旋转[sym] (下一个元素-符号符号符号) 矢量版本 (定义符号[\\v]) (

我已经编写了两次相同的函数,分别使用列表和向量。函数查找一个元素并返回集合中的下一个元素,如果找到的元素位于末尾,则将其换行<如果找不到元素,则返回code>nil

列表版本
(def syms'(\<\^\>\v))
(定义下一个元素-[coll元素]
(循环[coll rest coll]
(续)
(空?coll rest)无
(=(第一列)元素)(第n列第1列(第一列))
:else(重复出现(rest coll rest(())))
(defn向左旋转[sym]
(下一个元素-符号符号符号)
矢量版本
(定义符号[\<\^\>\v])
(定义下一个索引-[coll i]
(让[元素计数(coll计数)]
(续)
(或(i元素计数))-1
(=i(dec元素计数))0
:else(inc i)))
(defn向左旋转[sym]
(让[i(.indexOf syms sym)]
(获取syms(下一个索引-syms i)nil)))
测验
(断言(\<(向左旋转\v)))
(断言(=nil(向左旋转\o)))
哪个版本更好?我已经读到,在函数式编程中,列表通常是首选的,至少在F#向量(有数组)中是可变的,这不是我需要的。处理索引也会让人感觉很尴尬,但作为一个非功能性程序员,更容易让人感到头晕目眩

PS:这是我写的第一个函数程序之一,所以它可能不是最优的。
PPS:我是否正确使用反斜杠,还是应该使用其他东西来代替它?

第一版的
下一个元素-
更好,因为它可以处理任何序列。第二个版本依赖于序列来实现高效的索引访问,这很容易意外失败并获得低性能代码

建议:将
rest
更改为
next
。Rest有点不推荐,next在所有情况下都更好

还要避免使用列表。它们是非常特定的数据结构,很少需要。当你需要一个线性序列时,首先考虑向量。 代码的功能版本:

(defn next-elem- [coll elem]
  (->> (concat coll [(first coll)])
       (drop-while #(not= % elem))
       (second)))

Clojure向量是不可变的。还要注意,clojure列表实际上是隐藏在引擎盖下的64棵参差树。至于列表比向量更好,这要看情况。列表不是单独链接的列表吗?看这里:@Carcigenicate,我明白了,很有趣。不过,前面的链接提到列表与Java
LinkedList
Clojure列表实际上是单链接列表。根本不涉及树木;它们非常简单。向量被实现为分支因子为32的树。感谢您的帮助!我仍然很传统地认为这是一个很酷的实现
(def syms [\< \^ \> \v])

(defn next-index- [coll i]
  (let [elem-count (count coll)]
    (cond
      (or (< i 0) (> i elem-count)) -1
      (= i (dec elem-count)) 0
      :else (inc i))))

(defn rotate-left [sym]
  (let [i (.indexOf syms sym)]
    (get syms (next-index- syms i) nil)))
(assert (= \< (rotate-left \v)))
(assert (= nil (rotate-left \o)))
(defn next-elem- [coll elem]
  (->> (concat coll [(first coll)])
       (drop-while #(not= % elem))
       (second)))