惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
I
InfoQ
B
Blog RSS Feed
D
Docker
GbyAI
GbyAI
N
Netflix TechBlog - Medium
Y
Y Combinator Blog
F
Fortinet All Blogs
P
Proofpoint News Feed
Microsoft Azure Blog
Microsoft Azure Blog
人人都是产品经理
人人都是产品经理
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
M
MIT News - Artificial intelligence
C
Check Point Blog
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
博客园 - Franky
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
Last Week in AI
Last Week in AI
L
LangChain Blog

暗无天日

读:AI Agent 安全日志——从可见性与隐私的两难说起 - 暗无天日 读:AI Agent 生产化——一份从原型到上线的速查清单 - 暗无天日 AI写作的语言指纹——如何让文字不那么像机器 - 暗无天日 读:50 条 Claude Code 技巧——一个工程经理的六个月使用心得 读:AI 辅助开发为什么让 E2E 测试更有价值 - 暗无天日 读:在Emacs中使用Claude Code(Spacemacs适配版) - 暗无天日 Claude Code 背后的工程哲学——读 Agent Harness Engineering 读:Agent Harness Engineering——AI 智能体不只是模型,还有套件 - 暗无天日 browser-harness:让 AI 直接接管你的浏览器 - 暗无天日 读:Security-First CI/CD —— DevSecOps 自动化实践指南 TIL: 数字小键盘的小数点陷阱与行内算术求值 - 暗无天日 读:Immutability 不是万能药,它是一种权衡 - 暗无天日 Conducty:给 Claude Code 加上项目记忆和并行执行能力 - 暗无天日 读 — GitHub Trending 里的 Claude Code 技能包 读 — Prompt Caching 省钱指南 TIL: Emacs 中那些跟鼠标配合的冷门快捷键 - 暗无天日 读:Anvil——把 Emacs 变成 AI 的工具服务器 读:Emacs 代码折叠终极指南 - 暗无天日 读:Clojure 搭车客指南 - 暗无天日 git推送失败后恢复仓库损坏的完整记录 - 暗无天日 多智能体系统的两个有效模式——以及对 Claude Code 用户的启示 - 暗无天日 用 Org Babel 写 Literate 博文:扩展执行 + 定制导出 proced:Emacs 内置的进程查看器 - 暗无天日 从 proced 定制中学到的 Elisp 模式 读:让 Emacs proced 在 macOS 上显示 CPU 和内存 异步编程的函数着色税 - 暗无天日 hyperfine:命令行基准测试工具 - 暗无天日 管道中的变量去哪了?——子 shell 作用域陷阱 - 暗无天日 开源包装器的信任陷阱:四个危险信号 - 暗无天日 程序员愿意为 AI 写文档,却不愿为同事写 - 暗无天日
链式调用的代价:JavaScript 和 Clojure 的共同教训 - 暗无天日
2026-04-25 · via 暗无天日

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

即使只需要第一个结果, filtermap 也处理了整个数组。用 find 才能提前退出:

const user = users.find(u => u.active);
console.log(user?.name);
Alice

Clojure 的 filtermap 返回惰性序列,理论上只在有消费者需要数据时才计算元素。但 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 绑定好读。