Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 懒洋洋_Clojure_Stack Overflow_Lazy Evaluation_Lazy Sequences - Fatal编程技术网

Clojure 懒洋洋

Clojure 懒洋洋,clojure,stack-overflow,lazy-evaluation,lazy-sequences,Clojure,Stack Overflow,Lazy Evaluation,Lazy Sequences,我写了以下内容: (fn r [f xs] (lazy-seq (if (empty? xs) '() (cons (f (first xs)) (r f (rest xs)))))) 要解决4clojure.com的问题#118: 它要求在不使用map等的情况下重新实现map,并且该解决方案通过了测试(我不知道它是否正确:它与前面提到的其他解决方案非常接近) 因为这个问题说明它必须是懒惰的,所以我通过将我的解决方案“包装”在一个懒惰的序列中来编写上面的代码。。。然

我写了以下内容:

(fn r [f xs]
  (lazy-seq
    (if (empty? xs)
    '()
    (cons (f (first xs)) (r f (rest xs))))))
要解决4clojure.com的问题#118:

它要求在不使用map等的情况下重新实现map,并且该解决方案通过了测试(我不知道它是否正确:它与前面提到的其他解决方案非常接近)

因为这个问题说明它必须是懒惰的,所以我通过将我的解决方案“包装”在一个懒惰的序列中来编写上面的代码。。。然而,我不明白lazy seq是如何工作的

我不明白这里的“懒惰”是什么,也不知道如何测试它

当我问
(type…
时,毫不奇怪,我得到了一个clojure.lang.LazySeq,但我不知道这和如果我简单地删除懒惰的seq“wrapping”会得到什么区别

当然,如果我删除了懒惰的seq,我会得到一个stackoverflow,为什么要执行这个:

(= [(int 1e6) (int (inc 1e6))]
   (->> (... inc (range))
        (drop (dec 1e6))
        (take 2)))
否则(也就是说:如果我让懒惰的seq包装就位),它似乎可以正常工作

因此,我决定尝试以某种方式“调试”/跟踪正在发生的事情,以试图了解它是如何工作的。我使用了以下宏(我在SO IIRC上找到):

并将工作版本包装到dbg宏中,然后再次尝试执行它。现在kaboom:运行良好的版本现在也抛出堆栈溢出

现在我不确定:也许这是宏的一个不必要的影响,它会以某种方式强制评估那些本来不会被评估的东西

如果有人能用这个简单的函数和简单的测试来解释lazyness在这里是如何工作的,什么时候被调用,等等,那就太好了。

整个魔法在于java类。它本身实现ISeq接口,并且将s-expressions参数转换为不带任何参数的函数,并传递给clojure.lang.LazySeq的构造函数(传递给以
IFn
对象为参数的构造函数)因为最后您再次调用了
r
函数(返回的是
ISeq
,而不是完整的列表),这就允许懒散的seq评估项目

基本上,流程是这样的:

  • LazySeq调用传递给它的Fn(即代码的其余部分)
  • 此Fn调用返回ISeq,因为列表实现ISeq。由于递归调用
    r
    ,此返回ISeq(列表),第一个值作为具体值,第二个是LazySeq对象。返回的ISeq存储在类中的局部变量中
  • LazySeq在调用next item时的ISeq实现确实调用了它在上述步骤中存储在本地类变量中的下一个ISeq(列表),并检查它是否属于LazySeq类型(由于
    r
    call,它将位于第二个item中),如果是LazySeq,则计算并返回该值,然后返回item,否则直接返回该item(您传递给cons的第一个具体值)

我知道这有点让人心烦意乱:)。我刚才还浏览了Java代码,在我意识到这一神奇是可能的之后,我发现了这一点,因为对
r
本身的递归调用返回了一个惰性序列。这里有一种自定义分隔的连续体:)

这可能有助于澄清这个习惯用法中不涉及递归,因为
r
的返回值是一个
LazySeq
,只有在再次实现head调用
r
时才会出现。实现总是在
r
已返回后进行。Clojure具有“已实现”测试函数来测试是否已实现惰性序列的值。e、 g.(已实现?(范围))将为false。
(defmacro dbg [x] `(let [x# ~x] (println "dbg: " '~x "=" x#) x#))