Jeremy Bowers 回应了一场关于「函数颜色」的争论,反驳「参数(如 Go 的 context.Context)也算颜色」的说法。他先把问题形式化成一个可判定的标准:假设要改动调用栈深处某个函数的某个属性,看改动会传播多远——可以完全被封装(只影响直接调用者并能在某处被吸收),还是不可逃避地波及栈上所有函数。前者的传播像一条随时能断的链表(普通参数),后者才是真正的颜色(async 是典型)。关键洞察是普通函数改动几乎总能在栈的某一段被「接住」并封装起来,这是结构化编程存在的基础;而颜色改动会跳过中间层、强加给岛内所有函数。他进一步承认真相比二值复杂,给出「部分颜色」的进阶视角:Haskell 的 STM 就靠把可访问事务变量的约束沿 IO 颜色传播,强制中间纯函数要么被提升进 STM 要么根本无法触碰 TVar;而 State 却不是颜色,因为可以把整份状态传来传去而不必扩散约束。于是他提议:颜色不是 async 本身的专利,而是「是否可被封装」的依赖形状。
核心要点
他把颜色定义成沿调用栈强制传播的变更依赖形状:改动不可封装、波及所有上层函数
普通参数改动像可随时断开的链表,几乎总能在栈的某段被封装吸收
Go 的 context 之所以不是颜色,因为任意函数都能用 context.Background() 就地接住
颜色改动会跳过中间层、强加给岛内所有函数,async 是典型例子
Haskell 的 STM 是「部分颜色」:靠 IO 色把访问 TVar 的约束强加给中间纯函数
而 State 不是颜色——整份状态可以传来传去而不扩散约束
金句
Any change to a function with the 'color' shape of dependencies is a color. Any change to a function that is shaped like the linked list is not a color.