跳转至

Ch13 §05 编程语言 · 讲解稿

章节定位: Ch13 工具层。教"用什么语言写程序": 类型系统 / 编程范式 / 编译原理 / 内存管理。 承接: §04 并发 (用程序实现) → §05 程序本身的语言设计 走向: 后续所有 AI 工程实践 (Python/C++/Rust) 篇幅: ~4200 字 / 阅读 12 分钟 / 讲解 25-30 分钟


一 · 一句话总览

编程语言 = 程序的语法 + 语义 + 类型 + 范式。AI 工程师主流用 Python (动态/高级), 性能关键用 C++/CUDA, 系统底层用 Rust。理解类型系统和编译, 是写出健壮 AI 代码的基础。


二 · 心智模型

维度 选项
类型 静态 vs 动态, 强 vs 弱
范式 命令式, 函数式, 逻辑式
编译 编译 vs 解释, JIT
内存 手动, GC, 所有权

三 · 章节主线 (5 段)

第 1 段 · 类型系统 (10 分钟)

3.1.1 静态 vs 动态

维度 静态 动态
检查时机 编译期 运行期
例子 Java, C++, Rust, Go Python, JS, Ruby
优势 早发现错误, IDE 提示 灵活, 写起来快
劣势 啰嗦, 写起来慢 运行时报错, 难重构
# Python 动态
def add(a, b):
    return a + b

print(add(1, 2))     # 3
print(add("a", "b")) # "ab"  # 类型混淆, 运行时才知
// Java 静态
public static int add(int a, int b) {
    return a + b;
}
// add("a", "b")  // 编译错误

3.1.2 强 vs 弱类型

维度 强 弱
转换 显式 (cast) 隐式
例子 Python, Haskell, Rust JS, PHP, C
"1" + 2 Python: TypeError JS: "12"

3.1.3 类型推导 (Hindley-Milner)

不用写类型, 编译器自动推导:

-- Haskell
add :: Num a => a -> a -> a  -- 类型签名 (可选)
add a b = a + b              -- 无需写类型, 编译器推导

ML / Haskell / Rust / Swift 部分支持。

3.1.4 泛型 / 多态

// Java 泛型
List<Integer> list = new ArrayList<>();
list.add(1);
Integer x = list.get(0);

3.1.5 实用建议

场景 推荐语言
AI 实验 Python (动态, 库多)
性能内核 C++ / CUDA
系统级 Rust (安全)
高并发服务 Go (goroutine)
推理引擎 C++ / Triton
快速原型 Python / JS

第 2 段 · 编程范式 (8 分钟)

3.2.1 命令式 (Imperative)

主流范式。状态 + 赋值 + 控制流。

total = 0
for i in range(10):
    total += i
print(total)  # 45

代表: C, Java, Python (部分)。

3.2.2 函数式 (Functional)

表达式 + 不可变 + 高阶函数。

-- Haskell
sumList :: [Int] -> Int
sumList = foldr (+) 0

-- 等价 Python (但有可变)
from functools import reduce
total = reduce(lambda a, b: a + b, range(10), 0)

代表: Haskell, Lisp, Erlang, Clojure, F#。

3.2.3 逻辑式 (Logic)

声明事实 + 查询。

% Prolog
likes(mary, food).
likes(mary, wine).
likes(john, wine).
likes(john, mary).

% 查询
?- likes(mary, X).
X = food ;
X = wine.

代表: Prolog, Datalog, SQL。

3.2.4 面向对象 (OOP)

类 + 继承 + 多态。

class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        raise NotImplementedError

class Dog(Animal):
    def speak(self):
        return "Woof"

代表: Java, C++, Python, Ruby, C#。

3.2.5 范式对比

范式 状态 适合
命令式 可变 通用
函数式 不可变 并发, 数学
逻辑式 关系 数据库, 知识图谱
OOP 封装 GUI, 业务

第 3 段 · Lambda 演算 (10 分钟)

3.3.1 三个基本元素

  • 变量: \(x\)
  • 抽象: \(\lambda x. e\) (匿名函数)
  • 应用: \(e_1 e_2\)

3.3.2 Church 数

\(c_n = \lambda f. \lambda x. f^n(x)\) (把 \(f\) 用 \(n\) 次)

\[c_0 = \lambda f. \lambda x. x$$ $$c_1 = \lambda f. \lambda x. f(x)$$ $$c_2 = \lambda f. \lambda x. f(f(x))\]

3.3.3 Church 布尔

\[\text{true} = \lambda x. \lambda y. x$$ $$\text{false} = \lambda x. \lambda y. y\]

3.3.4 Church 加法

\[\text{add} = \lambda m. \lambda n. \lambda f. \lambda x. m(f)(n(f)(x))\]
# Python 实现 Church 数
def church_numeral(n):
    return lambda f: lambda x: reduce(lambda acc, _: f(acc), range(n), x)

c3 = church_numeral(3)
add = lambda m: lambda n: lambda f: lambda x: m(f)(n(f)(x))
c5 = add(c2)(c3)

print(c5(lambda x: x + 1)(0))  # 5

3.3.5 Curry-Howard 对应

逻辑 程序
命题 类型
证明 程序
蕴含 函数
合取 乘积类型

例: id :: a -> a 对应 \(A \to A\) 的构造性证明。

3.3.6 应用

  • Haskell / ML 核心
  • Rust 闭包
  • Python lambda
  • JavaScript 箭头函数

第 4 段 · 编译原理 (8 分钟)

3.4.1 五阶段

源码 → 词法 → Token → 语法 → AST → 语义 → 中间代码 → 目标代码 → 机器码
        lex            yacc         type check    IR          ASM

3.4.2 前端 (Frontend)

  • 词法分析: int x = 5 → [INT, ID, '=', INT]
  • 语法分析: token 流 → AST
  • 语义分析: 类型检查, 作用域

3.4.3 后端 (Backend)

  • 优化: 常量折叠, 死代码消除, 循环展开
  • 寄存器分配
  • 指令选择
  • 汇编

3.4.4 LLVM IR

define i32 @add(i32 %a, i32 %b) {
entry:
    %result = add i32 %a, %b
    ret i32 %result
}

Clang / Rust / Swift / Julia 都用 LLVM 后端。

3.4.5 JIT 编译

运行时编译热点代码。代表: V8 TurboFan, HotSpot C2, PyPy, Julia。

# PyPy: JIT 自动加速 Python
pypy my_script.py  # 比 CPython 快 5-50×

3.4.6 AOT vs JIT

类型 编译时机 例子
AOT (Ahead-Of-Time) 部署前 C, Rust, Go
JIT (Just-In-Time) 运行时 Java, JS, Julia
混合 启动 AOT, 热点 JIT V8, PyPy

第 5 段 · 内存管理 (8 分钟)

3.5.1 手动管理

int* p = malloc(sizeof(int) * 10);
free(p);  // 必须手动释放, 否则泄漏

代表: C, C++。

3.5.2 GC 三算法

算法 思路 优劣
引用计数 引用数 = 0 时释放 简单, 但循环引用
标记-清除 从根遍历, 不可达释放 处理循环, 但碎片 + STW
复制 把存活对象复制到新空间 无碎片, 但 50% 浪费
分代 老对象多检查, 新对象多检查 折中, Java / V8

3.5.3 Rust 所有权 (Ownership)

fn main() {
    let s = String::from("hello");
    let s2 = s;  // s 失效, 所有权转移
    // println!("{}", s);  // 编译错误
    println!("{}", s2);
}

3.5.4 借用 (Borrow)

fn len(s: &String) -> usize {  // 借用, 不转移
    s.len()
}
let s = String::from("hello");
println!("{}", len(&s));  // s 仍可用

3.5.5 实战: 选择内存策略

场景 推荐
高性能内核 手动 / Rust
业务服务 GC (Go / Java)
嵌入式 手动
AI Python GC + numpy 内部手动

四 · 易错点 (5 条)

  1. 动态 ≠ 弱: Python 动态但强类型。
  2. 静态 ≠ 安全: C 静态但弱类型 (void* 转换)。
  3. 函数式 ≠ 无副作用: Haskell 也有 IO monad。
  4. JIT ≠ 永远快: 启动慢, 大型项目有时反而慢。
  5. Rust 所有权 ≠ GC: 编译期检查, 零运行时开销。

五 · 跨章连接

章节 关联
Ch07 §04 Transformer Python + PyTorch
Ch11 §05 VLA C++ / ROS
Ch12 §05 EGNN Python + CUDA
Ch14 §01 数据结构 类型化实现

六 · 自测 5 题

  1. 静态 vs 动态类型差别?
  2. 命令式 vs 函数式范式?
  3. Lambda 演算的 Church 数 \(c_3\)?
  4. 编译五阶段?
  5. Rust 所有权解决什么问题?

七 · 一句话总结

编程语言 = 语法 + 类型 + 范式 + 编译 + 内存管理。AI 工程师: Python (实验) + C++/CUDA (性能) + Rust (系统)。类型系统强 + 函数式不可变 = 高可靠。Ch13 五节至此讲完 — 离散数学 + 架构 + OS + 并发 + 语言, 是 AI 工程师的"系统栈"。


八 · 板书建议

[板书 1: 类型]
   静态 (Java) / 动态 (Python)
   强 (Python) / 弱 (JS)
   Hindley-Milner 推导

[板书 2: 范式]
   命令式 (C)
   函数式 (Haskell)
   逻辑式 (Prolog)
   OOP (Java)

[板书 3: Lambda]
   c_n = λf.λx.f^n(x)
   Curry-Howard: 类型 = 命题

[板书 4: 编译]
   词法 → 语法 → 语义 → IR → 目标
   LLVM, JIT (V8)

九 · 参考资料

  1. Pierce, "Types and Programming Languages" (TAPL)
  2. "Structure and Interpretation of Computer Programs" (SICP)
  3. LLVM Documentation
  4. Rust Book (doc.rust-lang.org/book)
  5. Ch07 §04 Transformer (本套书)