内部懒惰序列究竟如何正常工作

时间:2014-03-25 20:31:17

标签: clojure

我是关于clojure的新手,并且不清楚内部是如何正确地执行延迟序列,或者更具体地返回延迟序列的函数意味着仅在需要时才计算结果。例如,在以下示例中:

(defn fc-lazy [ fn xs ]
 (lazy-seq
  (if-let [ xss (seq xs) ]
   (cons (fn (first xs)) (fc-lazy fn (rest xs)))
  ())))

我打电话的时候:

(fc-lazy #(* % 2) (range 100))

结果将是100个数字的集合,这意味着fc-lazy函数将被调用100次,这对我来说是不清楚的;在这种情况下,我们堆叠了所有这100个函数,如果不是,为什么?

感谢。

2 个答案:

答案 0 :(得分:6)

我想它就是这样的。

lazy-seq

  • 将其表达式形式参数转换为函数形式
  • 将其编译为Clojure闭包(符合JVM类的JVM类上的invoke方法 IFn界面)
  • 将此函数类绑定到新的LazySeq对象
  • 在其中留下一个空洞,用于实现的序列。

在此阶段,不是评估产生序列的表达式,而是将表达式捕获为看起来像(因此是)序列的对象中的函数对象。

当需要实现序列的某些功能(例如firstnextseq)在LazySeq上调用时,

  • 它注意到空洞并调用捕获的闭包,
  • 用结果填充洞,
  • 所需功能的应用
  • 返回结果。

后续调用找到填充的孔,并立即返回其所需的方面。

所以,当你完成序列时,你会得到一百个电话,但一次一个,而不是一次完成。


如果需要任何更正,我将不胜感激。

答案 1 :(得分:2)

如果你在REPL中输入了这个:

(source lazy-seq)

你会得到:

  

(defmacro lazy-seq
    “采用一组返回ISeq或nil的表达式,然后产生     一个Seqable对象,它将仅在第一次seq时调用主体     被调用,并将缓存结果并在随后的所有内容中返回     seq电话。另见 - 实现?“
    {:添加“1.0”}
    [&安培;正文]
    (列出'new'clojure.lang.LazySeq(list *'^ {:once true} fn * [] body)))

然后看看:LazySeq类。

请记住,在REPL中测试时会实现延迟序列。