习惯用语“将条件判断上移和循环下移”源自 TigerBeetle 的 Tiger Style 文档,并被诸如 matklad 和 Debasish Ghosh 等开发者讨论。其核心原则是通过将条件语句(if)向外移动到调用方或数据处理流水线的更早阶段,同时将迭代循环(for)向内移动到可以批量处理数据的后期阶段,从而集中控制流。这种分离旨在通过使函数的前置条件在其类型中显式化以及使热循环能够无分支运行,来简化函数,从而提升清晰度和性能。
在实践中,将条件判断上移意味着把一个内部检查无效输入(例如 Option 类型中的 None)的函数转换为由调用者处理这种情况、而函数本身假设输入有效的形式。例如,函数 `frobnicate(walrus: Option<Walrus>)` 在内部检查 None 可以被修改为调用者先过滤掉 None 值,然后将 `Vec<Walrus>` 传递给 `frobnicate_batch`,后者随后在没有任何条件检查的情况下处理该批次。同样,将循环下移指的是用一个处理整个集合的批处理函数替换每个元素调用标量函数的循环,这样可以分摊启动成本并提供向量化的机会。此类变换的代数基础由 filter-map 等价性说明:`filter p . map f == map f . filter (p . f)`,这得益于 `catMaybes` 的自然性,并且在 `p . f` 简化为输入数据上的廉价谓词时可以节省工作量。
然而,这一习惯用法并不普遍适用。将条件判断从循环中移出仅在条件与循环无关(循环不变)时才有效;否则,决策必须保留在数据变化的位置。在数据库查询优化中,将选择下推到连接之下仅在谓词仅引用连接一方的列时才是安全的,以确保连接的语义不变。同样,filter-map 重写仅在 `p . f` 能够简化为原始输入上的廉价谓词时才能节省计算量,因为否则重写后的形式仍会在测试之前对每个元素计算 `f`。因此,该习惯用法的有效性取决于识别诸如单态包含或自然性之类的代数性质——这些性质能够保证变换保持语义不变,同时可能降低成本。
