我是Clojure的新手,并试图简明地编写一个递归函数,将两个已排序的序列合并为一个新的排序序列。
这是我的尝试,无法编译:
(defn seq-merge [a-seq b-seq]
(cond
(empty? a-seq) b-seq
(empty? b-seq) a-seq
:else (let (if (< (first a-seq) (first b-seq))
[f (first a-seq) r (rest a-seq) h b-seq]
[f (first b-seq) r (rest b-seq) h a-seq])
(cons f (seq-merge r h)))))
最初,我想要这样的东西:
(if condition
(let [...]
(let [...]
(code-that-uses-conditional-bindings))
但似乎每个'let'都需要直接遵循代码,所以这不起作用。
目标是如果可以避免,则不必重复(cons f (seq-merge r h))
行两次。
我目前的解决方案是:
(defn seq-merge [a-seq b-seq]
(cond
(empty? a-seq) b-seq
(empty? b-seq) a-seq
:else (let [a-low? (< (first a-seq) (first b-seq))
f (if a-low? (first a-seq) (first b-seq))
r (if a-low? (rest a-seq) (rest b-seq))
h (if a-low? b-seq a-seq)]
(cons f (seq-merge r h)))))
但是,对于每个绑定值都有一个“if”,这似乎很笨拙。
答案 0 :(得分:2)
您可以尝试使用destructuring。在这种情况下,它没有奇迹,但它可以说有点清洁。
(defn seq-merge [a-seq b-seq]
(cond
(empty? a-seq) b-seq
(empty? b-seq) a-seq
:else (let [[f r h] (if (< (first a-seq) (first b-seq))
[(first a-seq) (rest a-seq) b-seq]
[(first b-seq) (rest b-seq) a-seq])]
(cons f (seq-merge r h)))))
通过非常简单的改变,你也可以使它变得懒惰。这样它就不会溢出堆栈,它将与无限列表一起使用。
(defn seq-merge [a-seq b-seq]
(lazy-seq
(cond
(empty? a-seq) b-seq
(empty? b-seq) a-seq
:else (let [[f r h] (if (< (first a-seq) (first b-seq))
[(first a-seq) (rest a-seq) b-seq]
[(first b-seq) (rest b-seq) a-seq])]
(cons f (seq-merge r h))))))
答案 1 :(得分:2)
在函数参数和let中使用destructuring可以将它清理一下:
(defn seq-merge [[a & as :as a-seq] [b & bs :as b-seq]]
(cond
(empty? a-seq) b-seq
(empty? b-seq) a-seq
:else (let [[f r h]
(if (< a b) [a as b-seq] [b bs a-seq])]
(cons f (seq-merge r h)))))