代数效应三语言对比:C++ 协程、Python 生成器与 Java 的缺席
一、从一个异常办不到的需求说起做过 CLI 工具或者协议解析的人都遇到过这种需求: 我走到第 3 步发现要问一下环境("这个文件存在吗"/"用户选哪个"),拿到答案之后还要从第 3 步继续往下走。 throw 办不到。异常是单向的,throw 出去的瞬间,当前函数的栈帧就被展开销毁了,catch 手里只剩下一个异常对象,第 3 步的局部变量、循环位置、执行到哪一行——全没了。你只能从头再跑一遍,或者把状态手工拆出来存进一个上下文对象里。 这就是代数效应(algebraic effects) 想解决的问题:把"中断"和"恢复"拆开,中断的人可以把当前位置之后的整段计算(续延,continuation)打包交出去,处理的人决定怎么用它——接着跑、跑两次、或者干脆扔掉。 flowchart TB subgraph EX[异常:单向栈一展开就回不去] E1[调用 f] --> E2[f 内 throw] --> E3[栈帧逐个销毁] --> E4[cat...
命名空间三语言对比:C++ namespace、Python 模块与 Java 包
一、概念引入:命名冲突是怎么来的写代码写到一定规模,几乎人人都会撞上同一个尴尬: 两个第三方库都定义了一个 connect(),你 #include 进来、或者 import 进来,一调用——编译器报"重定义"、解释器静默覆盖、或者 IDE 里一片飘红。名字没变,含义变了,程序行为就跟着崩。 这就是命名冲突(name collision):当多个名字相同、含义不同的实体被塞进同一个"符号空间",编译器或解释器就无法区分它们。 解决思路其实很朴素——给每个名字加一个"前缀",把一个大空间拆成若干互不干扰的小格子。这个"格子"就是命名空间(namespace): 全局符号空间(无命名空间时) connect() 库 A 的实现 connect() 库 B 的实现 冲突! ↓ 加前缀,拆格子 ↓ netA::connect() netB::connect() 自己的 connect() 三巨头语言各自给这个"...

