PROGRAMMING LANGUAGE THEORY · PLT

编程语言理论可视化实验室

从 Lambda 演算到内存模型,八个交互式可视化模块带你深入编程语言的核心理论。每个模块都包含可交互的 SVG 图形、实时控制面板与统计数据,纯 HTML/CSS/JS + SVG 实现,零外部依赖。

8 Modules SVG + Vanilla JS Zero Dependencies Single File
01LAMBDA CALCULUS

Lambda 演算

Lambda 演算是函数式编程的数学基础。这里展示 β-归约(β-reduction)与 α-转换(α-conversion):将抽象应用于参数时进行变量替换,必要时重命名绑定变量以避免变量捕获。

归约过程可视化
变量 Var
抽象 λx.
应用 @
当前归约点
β-归约规则:(λx.M) N → M[x:=N]。左下方选择预设表达式或自行输入,点击「归约一步」执行最外层归约,「完整归约」直到不可再归约。
02TYPE SYSTEMS

类型系统

Hindley-Milner 类型推断算法通过合一(unification)在 AST 上传播类型约束,自动推断表达式类型。切换 let-多态可观察 `let id=λx.x in id id` 在多态下推断为 a→a,在单态下发生 occurs check 失败。

类型推断与约束传播
Int
Bool
函数类型
类型变量
HM 算法原理:为每个节点分配类型变量,通过 unification 求解约束。let-多态会对 let 绑定的值进行泛化,使其可在不同类型处被实例化复用。
03GARBAGE COLLECTION

垃圾回收

三种经典 GC 算法对比:Mark-Sweep 标记可达后清除、Copying 复制存活对象到半区并压缩、Generational 按代龄分代回收。分配对象、建立引用、触发回收,观察堆空间前后变化。

堆内存与回收过程
可达对象
垃圾(将被回收)
根集 Root
已释放
GC策略:从根集(栈/全局变量)出发追踪引用图,未被标记的对象即为垃圾。分代假设:多数对象朝生夕灭,年轻代回收更频繁。
04INTERPRETER

解释器

树遍历解释器(tree-walking interpreter)递归求值 AST。逐步执行可观察 eval 调用顺序与环境栈的演变:let 绑定扩展环境,变量查找沿环境链读取,if 根据条件选择分支。

执行轨迹与环境
当前求值节点
已求值
let 绑定
数值/布尔
eval求值规则:字面量返回自身;变量查环境;let 先求值绑定再扩展环境求值体;if 求值条件后选择分支;二元运算先求值两子节点再计算。
05CLOSURES

闭包

闭包 = 函数代码 + 被捕获的环境。当内部函数引用外部作用域变量时,即使外层函数已返回,捕获的环境依然存活。此处可视化环境链与捕获变量的生命周期。

环境链与捕获变量
全局环境
捕获的环境
调用帧
捕获变量
闭包机制:makeAdder(10) 返回的闭包捕获了 x=10。即使 makeAdder 调用结束,闭包仍持有该环境,调用 adder(5) 时沿环境链找到 x,计算 10+5=15。
06MONADS

Monads

单子用 bind (>>=) 串联计算,封装上下文副作用。Maybe 处理失败短路、List 表达非确定性多重结果、State 传递可变状态。观察值如何流经 bind 链并发生类型变换。

Bind 链与类型变换
Just / 成功值
Nothing / 失败
列表元素
状态值
>>= bind:m >>= f 将 f 应用于 m 解包后的值。Maybe 中 Nothing 短路;List 中 f 返回列表需 concat 扁平化;State 中传递 (值, 状态) 对并更新状态。
07MACRO SYSTEMS

宏系统

卫生宏(hygienic macro)在展开时自动重命名绑定变量,避免变量捕获。展开前是宏调用语法树,展开后宏节点被替换为模板填充结果。对比展开树前后的结构差异。

宏展开树
宏调用
展开结果
模板参数
绑定(卫生重命名)
卫生展开:swap(a,b) 宏引入临时变量 tmp,卫生宏确保该 tmp 不会与调用点既有的 tmp 冲突,通过 gensym 重命名为 tmp#1 实现隔离。
08MEMORY MODELS

内存模型

栈与堆的布局,以及值语义与引用语义的差异。切换语言观察:C 的手动栈/堆、Rust 的所有权移动、Java 的引用对象、Python 的一切皆对象引用。分配变量看其在内存中的位置。

栈 / 堆内存布局
栈(值)
堆(对象)
引用/指针
所有权移动
语义对比:C 中 struct 默认栈上值拷贝;Rust let b=a 移动所有权使 a 失效;Java 对象在堆、变量存引用;Python 变量皆是引用绑定到堆对象。