【问题标题】:Reimplementing clojure's lazy seq重新实现 clojure 的惰性序列
【发布时间】:2025-11-27 09:00:01
【问题描述】:

我正在尝试重新实现 Clojures lazyseqs 作为学习练习,我正在尝试弄清楚 LazySeq.java 中发生了什么,

https://github.com/richhickey/clojure/blob/20090320/src/jvm/clojure/lang/LazySeq.java

这个分支不应该有分块行为,所以我的想法是假设每次第一次调用时都调用 fn,但我不知道 seq 调用是做什么的?更具体地说,以下行,

s = RT.seq(fn.invoke());

【问题讨论】:

    标签: clojure lazy-evaluation


    【解决方案1】:

    lazy-seq 宏的主体被放入一个函数中。当需要使用主体产生的序列时,它只是调用该函数来执行主体。您可以或多或少地通过以下方式重新实现lazy-seq

    (defn simple-lazy-seq*
      [seq-producing-fn]
      (reify
        clojure.lang.Sequential
        clojure.lang.Seqable
        (seq [this] (seq (seq-producing-fn)))))
    
    (defmacro simple-lazy-seq
      [& body]
      `(simple-lazy-seq* (fn [] ~@body)))
    

    来自核心的lazy-seq 也提供了ISeq 接口,但这并不是绝对必要的。

    编辑:用纯 Java 做事。

    static Seqable lazy_seq(IFn seq_generating_fn) {
        return new Seqable() {
            ISeq seq() {
                return RT.seq(seq_generating_fn.invoke());
            }
        }
    }
    
    YourClass.lazy_seq(new IFn() {
        Object invoke() {
            return thing.returning_the_seq();
        }
    });
    

    我不确定我的语法细节是否正确,但应该很接近。如您所见,这里有一些限制。例如。 thing 必须是 final IIRC。但是我的 Java 不是很流利。

    【讨论】:

    • 感谢您的解释,但是假设您有一个可以调用的 fn 对象,您将如何在纯 java 中解决这个问题。
    • @hamza-yerlikaya 这就是 Java 代码的作用。另请参阅编辑。