如何在Clojure

时间:2017-09-28 19:28:27

标签: if-statement clojure let

我是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”,这似乎很笨拙。

2 个答案:

答案 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)))))