在lazy-seq上无限循环

时间:2018-09-24 12:45:44

标签: clojure

为什么用butlast进行的第二次评估在Clojure中不断循环?

user=> (->> (range) butlast lazy-seq (take 0))
()
user=> (->> (range) butlast lazy-seq first) ; ...

Haskell中的等效项可以合理地进行懒惰评估。

ghci> take 0 . init $ [0..]
[]
ghci> head . init $ [0..]
0

修改

take 0不能操作,如下所述。

2 个答案:

答案 0 :(得分:2)

  

为什么第二个评估在Clojure中不断循环?

butlast是惰性的,因为它枚举了整个输入序列并建立了一个新的集合,直到耗尽所有输入为止。

在两个版本中,butlast消除了上游懒惰,因此我认为另一个相关的问题是“为什么在涉及butlast时第一个版本会返回?”:take 0是否-op —当 n 不是正数时,它不占用输入序列,因此无论传递什么都无所谓。

此外,我认为与head . tail $ [0..]等效的Clojure代码将是:

(->> (range) rest first) ;; => 1

butlast与您想要的相反。

答案 1 :(得分:1)

如果看一下butlast的实现,您会发现它很急切(使用loop而不是lazy-seq)。另一种懒惰的实现会做您想要的事情:

(defn butlast'
  "Like clojure.core/butlast but lazy."
  [xs]
  (when (seq xs)
    ((fn f [[x & xs]]
       (if (seq xs)
         (lazy-seq (cons x (f xs)))
         ()))
     xs)))