陷入了clojure的递归 - 错过了一个括号

时间:2013-10-24 18:44:59

标签: recursion clojure

我正在写一个clojure递归函数,所以给出:

(luty [1 2 3 4])

应该有这样的输出:

((1 2 3 4) (2 3 4) (3 4) (4) ()

我的代码是:

(defn luty [a1]
 (if (empty? a1)
   (list )
     (cons (seq a1)  (luty (rest a1) )
  )))

我得到了输出:

((1 2 3 4) (2 3 4) (3 4) (4)) //comment missing a ()

有人可以告诉我哪里出错了吗?

3 个答案:

答案 0 :(得分:2)

如果我们打印出这个过程并查看倒数第二个操作:

user> (defn luty [a1]
        (println "a1 is" a1)
         (if (empty? a1)
             ()
           (cons (seq a1) (luty (rest a1)))))
#'user/luty
user> (luty [1 2 3 4])
a1 is [1 2 3 4]
a1 is (2 3 4)
a1 is (3 4)
a1 is (4)
a1 is ()
((1 2 3 4) (2 3 4) (3 4) (4))
user> (cons '(4) ())
((4))

我们可以看到,将(4)添加到空列表的结果为((4)),而不是((4) ()),这是您最想要的。这可以通过使基本案例成为包含空列表的列表而不仅仅是空列表

来解决
user> (defn luty [a1]
         (if (empty? a1)
           '(())
           (cons (seq a1) (luty (rest a1)))))
#'user/luty
user> (luty [1 2 3 4])
((1 2 3 4) (2 3 4) (3 4) (4) ())

答案 1 :(得分:1)

cons的返回值是一个列表,第一个参数作为第一个元素,列表的其余部分作为第二个参数。如果第二个参数为空或nil,则表示您获得一个列表,其中第一个参数为单个成员。

这样做的原因是列表(概念上,至少在clojure中)具有2空格单元的链表; head元素的一个指针和尾部的一个指针(另一个列表,在clojure中保证是类似seq的东西 - 在许多其他lisps中你可以将第二个指针设置为你想要的任何值,所以你不是保证从那里得到一个“正确”的列表)。 “tail”位置的nil标志着列表的结尾。

列表是最容易实现且易于理解的持久性(在不可变的,结构共享的clojure意义上)数据结构。

答案 2 :(得分:1)

只是为了给你一个不同的方式来看待它:

user> (defn luty [a1]
        (reductions (fn [c _] (rest c)) (or (seq a1) '()) (-> a1 count range)))
   => #'user/luty
user> (luty [1 2 3 4])
   => ((1 2 3 4) (2 3 4) (3 4) (4) ())
user> (luty [])
   => (())
user> (luty nil)
   => (())