【问题标题】:Recursively building up cons lists递归建立缺点列表
【发布时间】:2016-03-23 22:18:34
【问题描述】:

我正在编写一个程序,它使用经典的 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 集合转换为 cons 列表:

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

这可行,但如果xs 太大会溢出。 recur 不起作用,因为递归调用不在尾部位置。将loop 与累加器一起使用是行不通的,因为cons 只会把东西放在前面,当每个递归都给你下一个 项时,我不能使用conj

我能做什么?

编辑:最后,事实证明,如果你得到这个工作,Clojure 从根本上不是为支持 cons 对而设计的(你不能将尾部设置为非序列)。我最终只是创建了一个自定义数据结构和 car/cdr 函数。

【问题讨论】:

  • 我认为,在返回结果之前,您可以使用 looprevert 其结果,而无需采取一些优化解决方法。
  • 您能否包含一个对Cons. 的示例调用以及它的输出

标签: recursion clojure tail-recursion cons


【解决方案1】:

像往常一样,我会提出最简单的循环/递归:

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

【讨论】:

  • 这行得通,但他特意要了一个懒惰的版本。否则,我只会使用reduce 或其他东西
【解决方案2】:

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

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

【讨论】:

  • 当我尝试运行这个解决方案时,我得到 java.lang.AbstractMethodError
  • @AlanThompson 我为我的帖子缩短了Cons 的定义。你需要实现empty
  • 使用像惰性序列这样复杂的东西似乎违背了说明“经典缺点对”的目的。
猜你喜欢
  • 1970-01-01
  • 2012-08-23
  • 2011-07-12
  • 2021-05-18
  • 1970-01-01
  • 2018-03-10
  • 2019-11-08
  • 2013-04-21
  • 2020-11-16
相关资源
最近更新 更多