为什么用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不能操作,如下所述。
答案 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)))