【发布时间】:2012-06-02 22:41:49
【问题描述】:
我写了以下内容:
(fn r [f xs]
(lazy-seq
(if (empty? xs)
'()
(cons (f (first xs)) (r f (rest xs))))))
解决 4clojure.com 的问题 #118:http://www.4clojure.com/problem/118
它要求在不使用 map 等的情况下重新实现 map 并且该解决方案通过了测试(我不知道它是否正确:它非常接近其他解决方案)。
因为问题表明它必须是懒惰的,所以我通过将我的解决方案“包装”在 lazy-seq 中来编写上面的代码......但是我不明白 lazy -seq 有效。
我不明白这里的“懒惰”是什么,也不知道如何测试它。
当我问(type ...) 时,不出所料,我得到了一个 clojure.lang.LazySeq,但我不知道这与我简单地删除 有什么区别惰性序列“包装”。
当然,如果我 remove lazy-seq 我会得到一个 stackoverflow 为什么要尝试执行此操作:
(= [(int 1e6) (int (inc 1e6))]
(->> (... inc (range))
(drop (dec 1e6))
(take 2)))
否则(即:如果我让惰性序列包装到位),它似乎工作正常。
所以我决定尝试以某种方式“调试”/跟踪正在发生的事情,以尝试了解它是如何工作的。我采用了以下宏(我在 SO IIRC 上找到的):
(defmacro dbg [x] `(let [x# ~x] (println "dbg: " '~x "=" x#) x#))
并将工作版本包装在 dbg 宏中并尝试再次执行它。现在 kaboom:运行良好的版本现在也会引发 stackoverflow。
现在我不确定:也许这是宏的一种不想要的效果,它会以某种方式强制对原本不会被评估的东西进行评估?
如果有人能解释一下,使用这个简单的函数和简单的测试,懒惰在这里是如何工作的,什么时候被调用,等等。
【问题讨论】:
-
Clojure 已经实现了?测试函数来测试惰性序列的值是否已经实现。例如(已实现?(范围))将是错误的。
标签: clojure stack-overflow lazy-evaluation lazy-sequences