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

时间:2019-01-27 18:47:34

标签: types clojure functional-programming containers

我已经写了两次相同的函数,分别使用一个列表和一个向量。该函数查找一个元素,然后返回集合中的下一个元素,如果找到的元素在末尾,则自动换行。如果找不到元素,则返回nil

列表版本

(def syms '(\< \^ \> \v))

(defn next-elem- [coll elem]
  (loop [coll-rest coll]
    (cond
      (empty? coll-rest) nil
      (= (first coll-rest) elem) (nth coll-rest 1 (first coll))
      :else (recur (rest coll-rest)))))

(defn rotate-left [sym]
  (next-elem- syms sym))

矢量版本

(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)))

哪个版本更好?我已经读过,列表在函数式编程中通常是首选,至少在F#向量(有数组)中是可变的,这不是我所需要的。处理索引也感觉很尴尬,但作为一个非功能性的程序员,您会更容易陷入困境。

PS:这是我编写的第一个功能程序之一,因此它可能不是最佳的。 PPS:我应该正确使用反斜杠还是应该在其位置使用其他内容?

1 个答案:

答案 0 :(得分:1)

next-elem-的第一个版本更好,因为它适用于任何序列。第二版依靠序列来进行有效的索引访问,这很容易导致意外失败并获得性能低下的代码。

建议:将rest更改为next。休息已被弃用,在所有情况下下一个都更好。

也避免使用列表。它们是非常具体的数据结构,很少需要。每当需要线性序列时,请先考虑向量。

代码的功能版本:

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