【问题标题】:Clojure lazy sequence usageClojure 惰性序列用法
【发布时间】:2011-06-26 21:52:08
【问题描述】:

我无法理解如何在 Clojure 中创建惰性序列。

我对宏的文档一无所知:

用法:(lazy-seq & body) 接受返回 ISeq 或 nil 的表达式体,并产生 一个 Seqable 对象,它只会在第一次 seq 时调用主体 被调用,并将缓存结果并在所有后续 seq 调用。

我见过的所有例子,似乎都做了如下的事情:

; return everything in the sequence starting at idx n
(defn myseq-after-n [n]
  (...)
)

(def my-lazy-seq
  (lazy-seq (conj [init-value] (myseq-after-n 2)))
)

所以,我不明白的第一件事是,由于lazy-seq 在对 conj 的调用之外,它如何防止 conj 在评估时生成无限序列?

我的第二个问题是,惰性序列定义总是采用这种一般形式吗?

【问题讨论】:

    标签: clojure functional-programming lazy-evaluation


    【解决方案1】:

    lazy-seq 调用仅在第一次访问时执行一次主体,然后缓存并在以后再次调用时返回相同的结果。

    如果您想使用它来构建长(甚至无限)序列,那么您需要在返回的序列中递归地嵌套其他惰性序列调用。这是我能想到的最简单的情况:

    (defn ints-from [n]
      (cons n (lazy-seq (ints-from (inc n)))))
    
    (take 10 (ints-from 7))
    => (7 8 9 10 11 12 13 14 15 16)
    

    任何 (ints-from n) 调用都会产生一个以 n 开头的序列,然后是一个惰性序列 (ints-from (inc n))。这是一个无限列表,但这不是问题,因为惰性序列确保 (int-from (inc n)) 仅在需要时才被调用。你可以在没有lazy-seq的情况下尝试完全相同的代码,你会很快得到一个StackOverflowError。

    lazy-seq 只是创建惰性序列的众多可能方法之一,它通常不是最方便的。以下是创建惰性序列的其他一些有趣/有用的方法:

    ; range is an easy way to get an infinite lazy sequence of integers, starting with zero     
    (take 10 (range))
    => (0 1 2 3 4 5 6 7 8 9)
    
    ; map produces lazy sequences, so the following is lazy 
    (take 10 (map #(* % %) (range)))
    => (0 1 4 9 16 25 36 49 64 81)
    
    ; iterate is a good way of making infinite sequenes of the form x, f(x), f(f(x))..... 
    (take 10 (iterate (partial * 2) 1))
    => (1 2 4 8 16 32 64 128 256 512)
    

    【讨论】:

    • 惰性序列不应该在缺点之外:(defn from [n] (lazy-seq (cons n (from (+ 1 n))))) ?
    • @andrew:你放什么顺序并不重要。将 cons 放在首位会稍微高效一些,因为这意味着第一个对象只是一个 cons 而不是包含 cons 的惰性序列。所以你少用一个对象.....不过没什么大不了的!
    • 嗯,这可能很重要,具体取决于具体情况。使用此代码,您正在急切地评估第一个成员。在你的情况下没问题,但并非总是如此。
    • 嗨,只是想了解lazy-seqs是如何工作的以及在clojure中的使用,这个答案仍然像以前一样相关吗?你能确认这个文件有next和rest的条款吗? clojure.org/lazy
    • 事实证明,如果你想使用实现的功能?要检查是否实现了惰性序列,您需要将 cons 放入惰性序列块中,因为 LazySeq 对象实现了 IPending 接口,而 clojure.lang.Cons 没有,无论如何它没有意义。这么悟?函数需要 LazySeq 参数。
    猜你喜欢
    • 2010-12-08
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 2015-06-12
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多