累加器上的reduce和map会产生堆栈溢出

时间:2016-09-21 07:28:04

标签: clojure stack-overflow lazy-evaluation

为什么我需要在这段代码中用map替换mapv以防止堆栈溢出:

#!/bin/bash lein-exec                                                           


(println (reduce (fn [acc _]                                                    
                   ;;(mapv #(inc %) acc))                                       
                   (map #(inc %) acc))                                          
                 (repeat 2 0)                                                   
                 (range (long 1e6))))           

我不明白懒惰时如何处理acc。感谢您的见解。

1 个答案:

答案 0 :(得分:4)

基本上,你得到的是大量嵌套的延迟序列,当被戳时,会导致堆栈溢出。

让我们看一下较小的例子:

(reduce (fn [acc _]
          (map inc acc))
        (repeat 2 0)
        (range 3))

由于map是懒惰的,因此上面的结果将是下一个:

(map inc (map inc (map inc (0 0)))

所以你并不急切地将acc映射到inc,而只是将懒惰序列一个放到另一个中,这将在之后实现。

返回range占用1e6的原始示例,结果如下:

(map inc 
    (map inc 
         (<... rougly 1e6 nested lazy sequences here ...>
            (map inc (0 0))) ...)

实现此操作将消耗大约1e6个堆栈帧,这肯定会导致堆栈溢出。

如果mapv没有涉及懒惰并立即实现acc,那么您的示例结果将在[1000000 1000000]完成后reduce完成。