递归建立缺点列表

时间:2016-03-23 22:18:35

标签: recursion clojure tail-recursion cons

我正在编写一个程序,它使用经典的cons对和Common Lisp,Scheme等等。

(deftype Cons [car cdr]
  clojure.lang.ISeq
    (first [c] (.car c))
    (more [c] (.cdr c))

我通过链接cons单元创建列表,例如(Cons. a (Cons. b nil))列表包含ab。我编写了一个将Clojure集合转换为缺点列表的函数:

(defn conslist [xs]
  (if (empty? xs)
      nil
      (Cons. (first xs) (conslist (rest xs)))))

这可行但如果xs太大则会溢出。 recur不起作用,因为递归调用不在尾部位置。将loop与累加器一起使用是行不通的,因为cons只会将内容放在前面,当每个递归器为您提供 next 项时,我无法使用{ {1}}。

我该怎么办?

编辑:最后,事实证明,如果你使用它,Clojure从根本上不是为了支持cons对(你不能将尾部设置为非seq)。我最终只是创建了一个自定义数据结构和car / cdr函数。

2 个答案:

答案 0 :(得分:2)

像往常一样,我会建议最简单的循环/重复:

(defn conslist [xs]
  (loop [xs (reverse xs) res nil]
    (if (empty? xs)
      res
      (recur (rest xs) (Cons. (first xs) res)))))

答案 1 :(得分:0)

lazy-seq是你的朋友。它需要一个评估为ISeq的主体,但在调用lazy-seq的结果之前不会对主体进行求值。

(defn conslist [xs]
  (if (empty? xs)
      nil
      (lazy-seq (Cons. (first xs) (conslist (rest xs))))))