How to Read Typing Rules [blog/lti/how_to_read]

对于初次接触编程语言理论的读者而言,文中遍布的数学符号与推导规则或许会显得有些陌生和令人生畏。 请不必担忧。这些形式化工具并非为了故作高深,恰恰相反, 它们是为了达到自然语言难以企及的精确性(precision)与无歧义性(unambiguity)。 本节将提供一份阅读这些规则的简单指南,熟悉的读者可以直接跳过。

读者可以将这些规则,看作是一门编程语言最根本的「物理定律」。它们以一种极为严谨的方式, 定义了什么样的程序是结构良好、有意义的,而什么样的程序则不是。

本文中的大多数规则,都呈现为如下的结构: $$\frac{\text{前提}_1 \quad \text{前提}_2 \quad ...}{\text{结论}} \quad (\text{规则名称})$$ 这条长长的横线,是理解一切的核心。

  • 横线上方:前提(Premises)
    • 这里列出的是一组条件假设
    • 只有当所有前提都得到满足时,这条规则才能被激活或使用。
  • 横线下方:结论(Conclusion)
    • 这是在所有前提都满足后,我们能够推导出的新事实
  • 右侧括号:规则名称 (Rule Name)
    • 这只是为了方便我们引用和讨论,给规则起的一个名字,如 VarApp

在规则的前提与结论中,您会反复看到一种形如 $\Gamma \vdash e : T$ 的核心判断(judgment)。让我们来拆解它的每一个符号:

  • $\Gamma$ (Gamma):这是上下文(Context)。它代表了我们进行推导时,所有已知的背景信息或假设。通常,它记录了变量已经被赋予的类型,例如:$x : \mathbb{Z},\ f : \mathrm{Bool} \to \mathrm{Bool}$。您可以把它看作是「在…的环境下」或「已知…」。
  • $\vdash$ (Turnstile):这个符号读作「推导出」或「证明」。它是上下文与待证论断之间的分隔符。
  • $e$:这是项(Term),即我们正在分析的那段程序代码。它可以是一个简单的变量 $x$,一个函数 $\mathsf{fun}(x)\ x + 1$,或是一个复杂的表达式。
  • $:$ 表示「拥有类型」(has type)。
  • $T$:这是类型(Type),例如 $\mathbb{Z}$、$\mathrm{Bool}$、$\mathrm{String} \to \mathbb{Z}$ 等。

将它们组合在一起,$\Gamma \vdash e : T$ 这整个判断的直白解读就是:「在上下文 $\Gamma$ 所提供的已知条件下,我们可以推导出(或证明),程序项 $e$ 拥有类型 $T$。」