

























JavaScript 的数组方法是 立即求值 的——每次调用 .filter() 或 .map() 都会遍历整个数组并生成新数组。所以:
const users = [ {name: "Alice", active: true}, {name: "Bob", active: false}, {name: "Carol", active: true}, {name: "Dave", active: true}, {name: "Eve", active: false} ]; const firstActiveName = users.filter(u => u.active).map(u => u.name)[0]; console.log(firstActiveName);
Alice
即使只需要第一个结果, filter 和 map 也处理了整个数组。用 find 才能提前退出:
const user = users.find(u => u.active); console.log(user?.name);
Alice
Clojure 的 filter 和 map 返回惰性序列,理论上只在有消费者需要数据时才计算元素。但 Clojure 的惰性序列是 分块 ( chunked )的——每次 realize 32 个元素,而不是严格地只 realize 需要的那一个。用一个带副作用的函数来看实际行为:
(defn process [x]
(println "Processing:" x)
(* x 2))
(->> (range 100)
(map process)
(filter #(> % 4))
first)
Processing: 0 Processing: 1 Processing: 2 Processing: 3 Processing: 4 Processing: 5 Processing: 6 Processing: 7 Processing: 8 Processing: 9 Processing: 10 Processing: 11 Processing: 12 Processing: 13 Processing: 14 Processing: 15 Processing: 16 Processing: 17 Processing: 18 Processing: 19 Processing: 20 Processing: 21 Processing: 22 Processing: 23 Processing: 24 Processing: 25 Processing: 26 Processing: 27 Processing: 28 Processing: 29 Processing: 30 Processing: 31 6
处理了 32 个元素就停了——正好是一个 chunk 的大小。对比 JavaScript 对同样 100 个元素全部处理,Clojure 的惰性求值确实省了一些工作,只是没有"只算到第三个就停"那么理想。chunked seq 是 Clojure 在惰性开销和性能之间的折衷:逐元素 realize 每次都要检查是否需要计算下一个元素,开销比分块处理大得多。如果集合很小(小于 32 个元素),整个集合都在一个 chunk 里,惰性求值跟立即求值没有区别。
所以 Clojure 的惰性序列更准确的说法是"按需分块计算"而不是"按需逐个计算"。但不管 Clojure 在性能上有多大优势,可读性问题依然存在——一条 5 步的 ->> 链在 Clojure 里依然不如拆成 let 绑定好读。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。