1

我正在编写一个 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 ()

有人可以建议我哪里出错了吗?

4

3 回答 3

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) ())
于 2013-10-24T18:51:27.040 回答
1

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

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

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

于 2013-10-24T19:44:43.813 回答
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)
   => (())
于 2013-10-26T20:51:48.953 回答