clojure - 在累加器上进行归约和映射会产生堆栈溢出

标签 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是如何处理的。感谢您的见解。

最佳答案

基本上,您得到的是大量嵌套的惰性序列,当它们被戳破时,会导致堆栈溢出。

让我们看一个更小的例子:

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

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

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

所以你并不是急于将 accinc 映射,而只是将惰性序列一个放入另一个,稍后再实现。

回到原始示例,其中 range 采用 1e6,结果如下:

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

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

如果 mapv 不涉及惰性,并且 acc 立即实现,因此示例的结果将是 [1000000 1000000] 就在 reduce 完成之后。

关于clojure - 在累加器上进行归约和映射会产生堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39610072/

相关文章:

clojure - 来自除 CL 之外的其他语言的 Clojure 功能概述

Clojure:查找向量向量中的最小值

c - 如何在 FreeRTOS 上模拟堆栈溢出

haskell - 如何将列表惰性地转换为这种类型?

Scala 2.8 和 map View

performance - Haskell中的懒惰和尾递归,为什么会崩溃?

clojure - 查找 clojure-contrib 库已移动到的位置

for-loop - :while and :when in clojure? 和有什么区别

Java数独回溯递归不断给出StackOverflow

F# StackOverflow in mono with continuations(启用尾调用消除)