Clojure 克洛朱尔:为什么我会被StackOverflower搞定? (定义abs[int] (如果(负整数)(*-1整数)整数) (修订动议) (让[[x y z]v] (续) (>x(absy))(map+v[011]) (或 (和(=x y)(位置x)(位置y)) (>y(absx))(map+v[-1011]) (或 (和(((绝对值x)y)(负x)(位置y)) (和(>yx)(>(absx)y))(map+v[0-11]) :其他(关联[x y z]0(inc x)2(inc z)) ;:else(map+v[1 0 1]) ))) (最后一次(花时间(fn[[x y z]](

Clojure 克洛朱尔:为什么我会被StackOverflower搞定? (定义abs[int] (如果(负整数)(*-1整数)整数) (修订动议) (让[[x y z]v] (续) (>x(absy))(map+v[011]) (或 (和(=x y)(位置x)(位置y)) (>y(absx))(map+v[-1011]) (或 (和(((绝对值x)y)(负x)(位置y)) (和(>yx)(>(absx)y))(map+v[0-11]) :其他(关联[x y z]0(inc x)2(inc z)) ;:else(map+v[1 0 1]) ))) (最后一次(花时间(fn[[x y z]](,clojure,Clojure,上面的代码使用各自的笛卡尔坐标构造螺旋整数。注意注释掉的部分:else(map+v[1 0 1])vs:else(assoc[x y z]0(inc x)2(inc z))。他们两个都工作。但是对于较大的值,例如,z

上面的代码使用各自的笛卡尔坐标构造螺旋整数。注意注释掉的部分
:else(map+v[1 0 1])
vs
:else(assoc[x y z]0(inc x)2(inc z))
。他们两个都工作。但是对于较大的值,例如,
z<10000
,我得到:
在clojure.lang.LazySeq/seq(LazySeq.java:51)处打印返回值(StackOverflowerError)时出错。空
。为什么?

map
是惰性的,它不是立即评估映射,而是堆叠映射函数,直到真正需要实现生成的集合。因此,当您需要第一个项目时,它将执行
(+v1(+v2(+v3..)
)等操作,并且最终会为大量的
贴图
堆叠而破坏堆栈

小例子:

(reduce (fn [acc _] (map + acc [1 1 1]))
        [0 0 0] (range 1000))
;; (1000 1000 1000)

(reduce (fn [acc _] (map + acc [1 1 1]))
        [0 0 0] (range 10000))
;; Error printing return value (StackOverflowError) at clojure.lang.LazySeq/sval (LazySeq.java:42).
;; null
你能做的就是用它的渴望的对应物,
mapv
替换
map

(reduce (fn [acc _] (mapv + acc [1 1 1]))
        [0 0 0] (range 10000))
;; [10000 10000 10000]

那么,为什么上面的代码适用于大值呢?还有三个几乎相同的
map
函数。
:else
部分中的
map
有什么特别之处?没有什么特别之处,因为您的
map
调用都是堆叠的,这取决于条件。因此实际上,它可能会从任何一个调用中抛出是的,但当前工作代码有三个相同的
map
函数,即使值非常大,它们也不会产生
溢出
错误。请参阅此文档列表,尤其是Clojure备忘单: