Clojure中的递归惰性序列

4
我不明白为什么这个lazy-seq会导致stackoverflow错误,而在将序列传递给dorun时却不会发生此错误:
(defn very-lazy [s]
    (lazy-seq
   (if (seq s)
     [(first s) (very-lazy (rest s))]
     [])))

(dorun (very-lazy (range 200000000)))
>nil

(take 2 (very-lazy (range 20000000))
>...(1577 (java.lang.StackOverflowError

如果它是懒惰的,那么take 2应该只让懒惰序列迭代两次,为什么不会发生,而且为什么dorun起作用?
1个回答

3
在你的示例中,函数返回lazyseq (0 (1 (2 (3 (...)))))。这就是为什么dorun可以运行而没有栈溢出(由于两个元素0(1 (2 (...)))的序列未被dorun求值),而second会失败(它返回无限嵌套的序列,repl试图对其进行求值以打印输出)。我猜你正在寻找这个解决方案。
(defn very-lazy [s]
  (lazy-seq
   (if (seq s)
     (cons (first s) (very-lazy (rest s)))
     [])))

(take 10 (very-lazy (range 200000000)))
-> (0 1 2 3 4 5 6 7 8 9)

在REPL中评估惰性序列常常会导致打印结果的问题,在正常使用中不会出现,例如仅在REPL中键入(repeat 1)是一个坏主意。 - Alex
1
你可以设置 *print-length* 来限制输出,例如 (set! *print-length* 10),在 repl 中执行 (repeat 1) 将会输出 (1 1 1 1 1 1 1 1 1 1 ...) - mobyte

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接