<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>类型系统学习专题 on FoldRight</title><link>https://www.foldright.com/type-system/</link><description>Recent content in 类型系统学习专题 on FoldRight</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="https://www.foldright.com/type-system/index.xml" rel="self" type="application/rss+xml"/><item><title>TAPL 数学预备知识：集合、关系与函数</title><link>https://www.foldright.com/type-system/tapl-math-preliminaries/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.foldright.com/type-system/tapl-math-preliminaries/</guid><description>
&lt;!doctype html&gt;
&lt;html lang="zh-CN"&gt;
&lt;head&gt;
&lt;meta charset="utf-8" /&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1" /&gt;
&lt;title&gt;TAPL 数学预备知识学习画布&lt;/title&gt;
&lt;style&gt;
:root{
--bg:#f7f5ef; --ink:#24221f; --muted:#746f66; --line:#ded7ca;
--card:#fffdf8; --accent:#2f6f73; --accent2:#9b5b35; --soft:#e8f1ee;
--good:#2f7d52; --bad:#b24b3d; --code:#f0ece3;
}
*{box-sizing:border-box}
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:var(--bg);color:var(--ink)}
header{padding:34px 22px 18px;border-bottom:1px solid var(--line);background:linear-gradient(180deg,#fffdf8,#f7f5ef)}
.wrap{max-width:1120px;margin:0 auto}
h1{font-size:clamp(28px,4vw,46px);line-height:1.08;margin:0 0 10px;letter-spacing:0}
.sub{font-size:17px;color:var(--muted);max-width:820px;line-height:1.7}
nav{position:sticky;top:0;z-index:5;background:rgba(247,245,239,.92);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
nav .wrap{display:flex;gap:8px;overflow:auto;padding:10px 22px}
nav a{white-space:nowrap;text-decoration:none;color:var(--ink);padding:8px 12px;border:1px solid var(--line);border-radius:999px;background:#fffaf1;font-size:14px}
main{padding:24px 22px 60px}
section{max-width:1120px;margin:0 auto 26px}
h2{font-size:24px;margin:0 0 14px}
h3{font-size:18px;margin:0 0 8px}
p{line-height:1.75;margin:8px 0}
.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
.grid2{display:grid;grid-template-columns:1.05fr .95fr;gap:14px}
.card{background:var(--card);border:1px solid var(--line);border-radius:8px;padding:16px}
.card strong{color:var(--accent)}
.tag{display:inline-block;font-size:12px;color:var(--accent);background:var(--soft);border:1px solid #c7ddda;border-radius:999px;padding:3px 8px;margin-bottom:8px}
code,.formula{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;background:var(--code);padding:2px 6px;border-radius:5px}
.formula{display:inline-block;margin:3px 0}
table{width:100%;border-collapse:collapse;background:var(--card);border:1px solid var(--line);border-radius:8px;overflow:hidden}
th,td{padding:12px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top;line-height:1.55}
th{background:#f0eadf;color:#37322b}
tr:last-child td{border-bottom:none}
button{cursor:pointer;border:1px solid var(--line);background:#fffaf1;color:var(--ink);border-radius:8px;padding:9px 12px;font:inherit}
button.active{background:var(--accent);color:white;border-color:var(--accent)}
.controls{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0 14px}
canvas{width:100%;height:260px;background:#fffdf8;border:1px solid var(--line);border-radius:8px}
.callout{border-left:4px solid var(--accent);background:#eef6f3;padding:12px 14px;border-radius:6px}
.warn{border-left-color:var(--accent2);background:#fbf1e9}
.mini{font-size:14px;color:var(--muted)}
.quiz label{display:block;margin:9px 0;padding:10px;border:1px solid var(--line);border-radius:8px;background:#fffdf8}
.answer{display:none;margin-top:10px;padding:10px;border-radius:8px;background:#eef6f3;color:#24483d}
.timeline{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
.step{background:var(--card);border:1px solid var(--line);border-radius:8px;padding:14px}
.step b{display:block;color:var(--accent);margin-bottom:6px}
@media (max-width:850px){.grid,.grid2,.timeline{grid-template-columns:1fr} h1{font-size:32px}}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;header&gt;
&lt;div class="wrap"&gt;
&lt;h1&gt;TAPL 数学预备知识学习画布&lt;/h1&gt;
&lt;p class="sub"&gt;这页把我们这次讨论的内容整理成一张可复习的网页：集合、关系、函数、偏函数、全函数、保持性，以及它们如何对应到小步语义、大步语义、类型关系和 Type Safety。&lt;/p&gt;
&lt;/div&gt;
&lt;/header&gt;
&lt;nav&gt;
&lt;div class="wrap"&gt;
&lt;a href="#map"&gt;总览&lt;/a&gt;
&lt;a href="#relation"&gt;关系到函数&lt;/a&gt;
&lt;a href="#preservation"&gt;保持性&lt;/a&gt;
&lt;a href="#tapl"&gt;TAPL 对照&lt;/a&gt;
&lt;a href="#quiz"&gt;快速自测&lt;/a&gt;
&lt;/div&gt;
&lt;/nav&gt;
&lt;main&gt;
&lt;section id="map"&gt;
&lt;h2&gt;一张总览图&lt;/h2&gt;
&lt;div class="grid"&gt;
&lt;div class="card"&gt;
&lt;span class="tag"&gt;基础对象&lt;/span&gt;
&lt;h3&gt;集合 Set&lt;/h3&gt;
&lt;p&gt;集合是一堆对象的容器，例如 &lt;code&gt;N = {0,1,2,...}&lt;/code&gt;。后面的关系、函数、谓词，都建立在集合之上。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;span class="tag"&gt;核心抽象&lt;/span&gt;
&lt;h3&gt;关系 Relation&lt;/h3&gt;
&lt;p&gt;关系就是一堆元组。二元关系 &lt;code&gt;R ⊆ S × T&lt;/code&gt; 可以理解为从左边对象到右边对象的箭头集合。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;span class="tag"&gt;特殊关系&lt;/span&gt;
&lt;h3&gt;函数 Function&lt;/h3&gt;
&lt;p&gt;函数是“输出唯一”的关系。偏函数允许某些输入没有结果；全函数要求每个输入都有唯一结果。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="relation"&gt;
&lt;h2&gt;从关系理解偏函数和全函数&lt;/h2&gt;
&lt;div class="grid2"&gt;
&lt;div class="card"&gt;
&lt;h3&gt;交互图：看每个输入有几条箭头&lt;/h3&gt;
&lt;div class="controls"&gt;
&lt;button class="active" data-mode="relation"&gt;一般关系&lt;/button&gt;
&lt;button data-mode="partial"&gt;偏函数&lt;/button&gt;
&lt;button data-mode="total"&gt;全函数&lt;/button&gt;
&lt;/div&gt;
&lt;canvas id="relationCanvas" width="900" height="320"&gt;&lt;/canvas&gt;
&lt;p id="canvasText" class="mini"&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3&gt;判断口诀&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;一般关系：&lt;/strong&gt;同一个输入可以没有结果、一个结果、多个结果。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;偏函数：&lt;/strong&gt;每个输入最多一个结果。也就是：要么没定义，要么唯一。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;全函数：&lt;/strong&gt;每个输入恰好一个结果。也就是：既不能没有，也不能多个。&lt;/p&gt;
&lt;div class="callout"&gt;
&lt;p&gt;&lt;span class="formula"&gt;R ⊆ S × T&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="formula"&gt;偏函数：若 (s,t₁)∈R 且 (s,t₂)∈R，则 t₁=t₂&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="formula"&gt;全函数：偏函数 + dom(R)=S&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2&gt;几个容易混淆的点&lt;/h2&gt;
&lt;div class="grid"&gt;
&lt;div class="card"&gt;
&lt;h3&gt;undefined&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;f(x) ↑&lt;/code&gt; 表示 f 在 x 上无定义。比如 &lt;code&gt;pred(0)&lt;/code&gt; 在自然数前驱函数里无定义。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3&gt;fail&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;f(x)=fail&lt;/code&gt; 是一种明确返回的失败结果。失败是可观察的结果，可以被建模为 &lt;code&gt;T ∪ {fail}&lt;/code&gt;。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3&gt;divergence&lt;/h3&gt;
&lt;p&gt;发散表示算不完、不会返回。它和 fail 不一样：fail 是返回了失败，divergence 是没有返回。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="preservation"&gt;
&lt;h2&gt;保持性：把它理解成“不变式”&lt;/h2&gt;
&lt;div class="grid2"&gt;
&lt;div class="card"&gt;
&lt;h3&gt;定义的白话版&lt;/h3&gt;
&lt;p&gt;如果 &lt;code&gt;s R s′&lt;/code&gt; 且 &lt;code&gt;P(s)&lt;/code&gt;，总能推出 &lt;code&gt;P(s′)&lt;/code&gt;，那么就说性质 P 被关系 R 保持。&lt;/p&gt;
&lt;p class="formula"&gt;∀s,s′. (s R s′ ∧ P(s)) ⇒ P(s′)&lt;/p&gt;
&lt;div class="callout"&gt;
&lt;p&gt;把 &lt;code&gt;R&lt;/code&gt; 想成“一步执行”，把 &lt;code&gt;P&lt;/code&gt; 想成“好性质”。保持性就是说：执行一步不会把好状态变坏。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="card"&gt;
&lt;h3&gt;数字例子&lt;/h3&gt;
&lt;p&gt;令 &lt;code&gt;S = Z&lt;/code&gt;，&lt;code&gt;x R y&lt;/code&gt; 表示 &lt;code&gt;y = x + 1&lt;/code&gt;，&lt;code&gt;P(x)&lt;/code&gt; 表示 &lt;code&gt;x ≥ 0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果 x 非负，那么 x+1 仍然非负，所以 P 被“加一”关系保持。&lt;/p&gt;
&lt;div class="callout warn"&gt;
&lt;p&gt;如果 R 改成 &lt;code&gt;y = x - 1&lt;/code&gt;，那么从 0 可以走到 -1，非负性被破坏，所以 P 不被保持。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="tapl"&gt;
&lt;h2&gt;放回 TAPL：关系、函数、类型安全&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;记号&lt;/th&gt;
&lt;th&gt;它是什么关系&lt;/th&gt;
&lt;th&gt;是否像函数&lt;/th&gt;
&lt;th&gt;直觉&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;t → t′&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;小步语义，&lt;code&gt;R ⊆ Tm × Tm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;通常是偏函数&lt;/td&gt;
&lt;td&gt;同一个 term 通常最多只有一个下一步；value 或 stuck term 没有下一步。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;t ⇓ v&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;大步语义，&lt;code&gt;R ⊆ Tm × Val&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;通常是偏函数&lt;/td&gt;
&lt;td&gt;如果能算出值，值通常唯一；若存在死循环，就不是全函数。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Γ ⊢ t : T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;类型关系，可看作 &lt;code&gt;(Γ,t) ↦ T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;简单类型系统里通常是偏函数&lt;/td&gt;
&lt;td&gt;类型唯一性说明同一个 term 在同一上下文下最多一个类型；ill-typed term 没有类型。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;typeof(Γ,t)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;实现里的类型检查函数&lt;/td&gt;
&lt;td&gt;常建模为全函数到 &lt;code&gt;Ty ∪ {fail}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;对每个输入都停机并返回：要么类型 T，要么 fail。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section&gt;
&lt;h2&gt;Type Safety 的核心句式&lt;/h2&gt;
&lt;div class="timeline"&gt;
&lt;div class="step"&gt;&lt;b&gt;1. 起点&lt;/b&gt;某个 term 是 well-typed：&lt;code&gt;Γ ⊢ t : T&lt;/code&gt;&lt;/div&gt;
&lt;div class="step"&gt;&lt;b&gt;2. 执行&lt;/b&gt;它走了一步：&lt;code&gt;t → t′&lt;/code&gt;&lt;/div&gt;
&lt;div class="step"&gt;&lt;b&gt;3. 保持&lt;/b&gt;执行后仍有类型：&lt;code&gt;Γ ⊢ t′ : T&lt;/code&gt;&lt;/div&gt;
&lt;div class="step"&gt;&lt;b&gt;4. 意义&lt;/b&gt;类型良好这个性质，被小步求值关系保持。&lt;/div&gt;
&lt;/div&gt;
&lt;div class="card" style="margin-top:14px"&gt;
&lt;p&gt;&lt;strong&gt;Preservation 定理：&lt;/strong&gt;如果 &lt;code&gt;Γ ⊢ t : T&lt;/code&gt; 且 &lt;code&gt;t → t′&lt;/code&gt;，那么 &lt;code&gt;Γ ⊢ t′ : T&lt;/code&gt;。&lt;/p&gt;
&lt;p class="mini"&gt;这正是 2.1.10 的定义在类型系统里的核心应用：well-typed 是 P，小步求值是 R。&lt;/p&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="quiz"&gt;
&lt;h2&gt;快速自测&lt;/h2&gt;
&lt;div class="card quiz"&gt;
&lt;h3&gt;1. &lt;code&gt;pred: N ⇀ N&lt;/code&gt;，其中 &lt;code&gt;pred(0)&lt;/code&gt; 无定义。它是什么？&lt;/h3&gt;
&lt;label&gt;&lt;input type="radio" name="q1"&gt; 一般关系，且不是偏函数&lt;/label&gt;
&lt;label&gt;&lt;input type="radio" name="q1" data-correct&gt; 偏函数，但不是全函数&lt;/label&gt;
&lt;label&gt;&lt;input type="radio" name="q1"&gt; 全函数&lt;/label&gt;
&lt;h3&gt;2. Preservation 在说什么？&lt;/h3&gt;
&lt;label&gt;&lt;input type="radio" name="q2"&gt; 每个程序都会停机&lt;/label&gt;
&lt;label&gt;&lt;input type="radio" name="q2" data-correct&gt; well-typed 这个性质被求值关系保持&lt;/label&gt;
&lt;label&gt;&lt;input type="radio" name="q2"&gt; 每个 term 都有类型&lt;/label&gt;
&lt;button id="check"&gt;检查答案&lt;/button&gt;
&lt;div id="ans" class="answer"&gt;答案：1 选“偏函数，但不是全函数”；2 选“well-typed 这个性质被求值关系保持”。你已经抓住这章最重要的桥了。&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/main&gt;
&lt;script&gt;
const canvas = document.getElementById("relationCanvas");
const ctx = canvas.getContext("2d");
const text = document.getElementById("canvasText");
const modes = {
relation: {
title: "一般关系：A 可以同时指向 1 和 2，所以输出不唯一。",
arrows: [["A","1"],["A","2"],["B","3"]]
},
partial: {
title: "偏函数：每个输入最多一条箭头；C 没有箭头，表示无定义。",
arrows: [["A","1"],["B","3"]]
},
total: {
title: "全函数：每个输入恰好一条箭头。",
arrows: [["A","2"],["B","3"],["C","1"]]
}
};
function draw(mode){
const w=canvas.width,h=canvas.height;
ctx.clearRect(0,0,w,h);
const left=["A","B","C"], right=["1","2","3"];
const lx=150, rx=740, top=80, gap=80;
ctx.font="22px system-ui";
ctx.fillStyle="#746f66";
ctx.fillText("S 输入集合",80,38);
ctx.fillText("T 输出集合",675,38);
const pos={};
left.forEach((n,i)=&gt;{pos[n]={x:lx,y:top+i*gap}; circle(lx,top+i*gap,n,"#e8f1ee","#2f6f73");});
right.forEach((n,i)=&gt;{pos[n]={x:rx,y:top+i*gap}; circle(rx,top+i*gap,n,"#fbf1e9","#9b5b35");});
modes[mode].arrows.forEach(([a,b])=&gt;arrow(pos[a].x+28,pos[a].y,pos[b].x-28,pos[b].y));
text.textContent=modes[mode].title;
}
function circle(x,y,label,fill,stroke){
ctx.beginPath(); ctx.arc(x,y,28,0,Math.PI*2); ctx.fillStyle=fill; ctx.fill(); ctx.lineWidth=2; ctx.strokeStyle=stroke; ctx.stroke();
ctx.fillStyle="#24221f"; ctx.textAlign="center"; ctx.textBaseline="middle"; ctx.font="22px system-ui"; ctx.fillText(label,x,y);
}
function arrow(x1,y1,x2,y2){
const ang=Math.atan2(y2-y1,x2-x1);
ctx.strokeStyle="#2f6f73"; ctx.lineWidth=3; ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke();
ctx.beginPath(); ctx.moveTo(x2,y2); ctx.lineTo(x2-14*Math.cos(ang-Math.PI/6),y2-14*Math.sin(ang-Math.PI/6)); ctx.lineTo(x2-14*Math.cos(ang+Math.PI/6),y2-14*Math.sin(ang+Math.PI/6)); ctx.closePath(); ctx.fillStyle="#2f6f73"; ctx.fill();
}
document.querySelectorAll("[data-mode]").forEach(btn=&gt;{
btn.addEventListener("click",()=&gt;{
document.querySelectorAll("[data-mode]").forEach(b=&gt;b.classList.remove("active"));
btn.classList.add("active"); draw(btn.dataset.mode);
});
});
document.getElementById("check").addEventListener("click",()=&gt;document.getElementById("ans").style.display="block");
draw("relation");
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</description></item><item><title>TAPL 数学预备知识：有序集、序列与归纳法</title><link>https://www.foldright.com/type-system/tapl-chapter-2-math-preliminaries/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://www.foldright.com/type-system/tapl-chapter-2-math-preliminaries/</guid><description>
&lt;!doctype html&gt;
&lt;html lang="zh-CN"&gt;
&lt;head&gt;
&lt;meta charset="utf-8"&gt;
&lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
&lt;title&gt;TAPL 数学预备知识：有序集、序列与归纳法&lt;/title&gt;
&lt;style&gt;
:root {
color-scheme: light;
--ink: #172033;
--muted: #637083;
--line: #d8e0ea;
--soft: #f5f7fb;
--paper: #ffffff;
--accent: #2563eb;
--accent-soft: #eaf1ff;
--green: #0f766e;
--green-soft: #e6f6f3;
--amber: #9a5b00;
--amber-soft: #fff3d8;
--rose: #be123c;
--rose-soft: #ffe8ee;
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
background: #eef3f8;
color: var(--ink);
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
line-height: 1.68;
}
a {
color: inherit;
}
.hero {
min-height: 92vh;
display: grid;
align-items: center;
background:
linear-gradient(115deg, rgba(255,255,255,.94), rgba(255,255,255,.78)),
radial-gradient(circle at 88% 20%, rgba(37,99,235,.18), transparent 30%),
radial-gradient(circle at 10% 82%, rgba(15,118,110,.15), transparent 32%),
#f4f7fb;
border-bottom: 1px solid var(--line);
}
.wrap {
width: min(1120px, calc(100% - 32px));
margin: 0 auto;
}
.hero-grid {
display: grid;
grid-template-columns: minmax(0, 1.08fr) minmax(320px, .92fr);
gap: 34px;
align-items: center;
padding: 48px 0;
}
.eyebrow {
margin: 0 0 12px;
color: var(--accent);
font-weight: 800;
letter-spacing: .06em;
text-transform: uppercase;
font-size: 13px;
}
h1 {
margin: 0;
max-width: 760px;
font-size: clamp(38px, 7vw, 72px);
line-height: 1.04;
letter-spacing: 0;
}
.subtitle {
max-width: 690px;
margin: 22px 0 0;
color: #354155;
font-size: 20px;
}
.quick-nav {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 28px;
}
.quick-nav a,
.pill {
display: inline-flex;
align-items: center;
min-height: 38px;
padding: 8px 13px;
border: 1px solid var(--line);
border-radius: 8px;
background: rgba(255,255,255,.82);
color: #273246;
font-weight: 700;
text-decoration: none;
font-size: 14px;
}
.map {
background: var(--paper);
border: 1px solid var(--line);
border-radius: 8px;
padding: 18px;
box-shadow: 0 18px 45px rgba(50, 67, 91, .12);
}
.map h2 {
margin: 0 0 14px;
font-size: 18px;
}
.map-flow {
display: grid;
gap: 10px;
}
.flow-row {
display: grid;
grid-template-columns: 116px 1fr;
gap: 10px;
align-items: start;
padding: 12px;
background: var(--soft);
border: 1px solid #e4eaf2;
border-radius: 8px;
}
.flow-row strong {
color: #1d2a3d;
}
.flow-row span {
color: var(--muted);
font-size: 14px;
}
main {
padding: 42px 0 70px;
}
section {
scroll-margin-top: 24px;
margin-top: 34px;
}
.section-head {
display: flex;
justify-content: space-between;
gap: 18px;
align-items: end;
margin-bottom: 16px;
}
h2 {
margin: 0;
font-size: 30px;
line-height: 1.15;
letter-spacing: 0;
}
.hint {
max-width: 620px;
margin: 8px 0 0;
color: var(--muted);
}
.grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.card {
background: var(--paper);
border: 1px solid var(--line);
border-radius: 8px;
padding: 18px;
}
.card h3 {
display: flex;
justify-content: space-between;
gap: 12px;
margin: 0 0 8px;
font-size: 20px;
line-height: 1.3;
}
.tag {
align-self: start;
padding: 4px 8px;
border-radius: 7px;
background: var(--accent-soft);
color: var(--accent);
font-size: 12px;
white-space: nowrap;
}
.card p {
margin: 8px 0 0;
}
.formula {
margin: 12px 0 0;
padding: 12px 14px;
overflow-x: auto;
border-radius: 8px;
border: 1px solid #dbe6f5;
background: #f8fbff;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 14px;
white-space: nowrap;
}
.compare {
width: 100%;
border-collapse: collapse;
overflow: hidden;
border-radius: 8px;
background: var(--paper);
border: 1px solid var(--line);
}
.compare th,
.compare td {
padding: 13px 14px;
border-bottom: 1px solid var(--line);
text-align: left;
vertical-align: top;
}
.compare th {
background: #edf4ff;
color: #1f3b65;
font-size: 14px;
}
.compare tr:last-child td {
border-bottom: 0;
}
.split {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(320px, .86fr);
gap: 14px;
}
.sequence-demo {
display: grid;
gap: 10px;
}
.seq {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.chip {
min-width: 38px;
min-height: 36px;
display: inline-grid;
place-items: center;
padding: 6px 10px;
border-radius: 8px;
background: #eaf1ff;
color: #1d4ed8;
font-weight: 800;
}
.operator {
color: var(--muted);
font-weight: 800;
}
.induction-board {
background: #111827;
color: #f8fafc;
border-radius: 8px;
padding: 18px;
}
.board-grid {
display: grid;
grid-template-columns: repeat(6, minmax(40px, 1fr));
gap: 7px;
margin-top: 12px;
}
.cell {
min-height: 42px;
display: grid;
place-items: center;
border: 1px solid rgba(255,255,255,.18);
border-radius: 7px;
color: #cbd5e1;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 13px;
}
.cell.done {
background: rgba(37, 99, 235, .75);
color: #fff;
}
.cell.current {
background: #fbbf24;
color: #231600;
font-weight: 900;
}
.legend {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 12px;
color: #cbd5e1;
font-size: 14px;
}
.callout {
border-radius: 8px;
padding: 18px;
border: 1px solid var(--line);
background: var(--paper);
}
.callout.blue {
background: var(--accent-soft);
border-color: #bfd3ff;
}
.callout.green {
background: var(--green-soft);
border-color: #b9e4dc;
}
.callout.amber {
background: var(--amber-soft);
border-color: #f1d28b;
}
.callout h3 {
margin: 0 0 8px;
}
details {
background: var(--paper);
border: 1px solid var(--line);
border-radius: 8px;
padding: 0;
}
summary {
cursor: pointer;
padding: 16px 18px;
font-weight: 800;
}
details &gt; div {
padding: 0 18px 18px;
color: #344054;
}
.steps {
display: grid;
gap: 12px;
counter-reset: step;
}
.step {
position: relative;
padding: 14px 14px 14px 48px;
background: var(--paper);
border: 1px solid var(--line);
border-radius: 8px;
}
.step::before {
counter-increment: step;
content: counter(step);
position: absolute;
left: 14px;
top: 14px;
width: 24px;
height: 24px;
display: grid;
place-items: center;
border-radius: 50%;
background: var(--ink);
color: #fff;
font-weight: 800;
font-size: 13px;
}
.memory {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
}
.memory .card {
min-height: 170px;
}
.active-card {
outline: 3px solid rgba(37, 99, 235, .35);
border-color: #8fb2ff;
}
footer {
padding: 28px 0 40px;
color: var(--muted);
border-top: 1px solid var(--line);
background: #f8fafc;
}
@media (max-width: 860px) {
.hero-grid,
.split,
.grid,
.memory {
grid-template-columns: 1fr;
}
.hero {
min-height: auto;
}
.section-head {
display: block;
}
}
@media (max-width: 520px) {
.wrap {
width: min(100% - 22px, 1120px);
}
h1 {
font-size: 38px;
}
h2 {
font-size: 25px;
}
.flow-row {
grid-template-columns: 1fr;
}
.board-grid {
grid-template-columns: repeat(3, minmax(40px, 1fr));
}
}
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;header class="hero"&gt;
&lt;div class="wrap hero-grid"&gt;
&lt;div&gt;
&lt;p class="eyebrow"&gt;Types and Programming Languages · Math Preliminaries&lt;/p&gt;
&lt;h1&gt;有序集、序列与归纳法学习画布&lt;/h1&gt;
&lt;p class="subtitle"&gt;把这次对话里的定义、翻译和直觉解释整理成一页：从关系与有序集，到序列，再到归纳法。目标是以后看到 TAPL 证明时，能迅速想起每个符号背后的意思。&lt;/p&gt;
&lt;nav class="quick-nav" aria-label="页面导航"&gt;
&lt;a href="#ordered"&gt;有序集&lt;/a&gt;
&lt;a href="#sequences"&gt;序列&lt;/a&gt;
&lt;a href="#induction"&gt;归纳法&lt;/a&gt;
&lt;a href="#lexicographic"&gt;字典序归纳&lt;/a&gt;
&lt;a href="#closure"&gt;闭包证明&lt;/a&gt;
&lt;/nav&gt;
&lt;/div&gt;
&lt;aside class="map" aria-label="知识地图"&gt;
&lt;h2&gt;这页怎么读&lt;/h2&gt;
&lt;div class="map-flow"&gt;
&lt;div class="flow-row"&gt;
&lt;strong&gt;关系性质&lt;/strong&gt;
&lt;span&gt;自反、对称、传递、反对称，是后面预序、偏序、等价关系的积木。&lt;/span&gt;
&lt;/div&gt;
&lt;div class="flow-row"&gt;
&lt;strong&gt;有序结构&lt;/strong&gt;
&lt;span&gt;预序看“能否到达”，偏序再要求“互相可达就必须相同”，全序要求任意两个都能比较。&lt;/span&gt;
&lt;/div&gt;
&lt;div class="flow-row"&gt;
&lt;strong&gt;边界对象&lt;/strong&gt;
&lt;span&gt;join 是最小上界，meet 是最大下界。它们经常出现在类型层级、子类型和格结构里。&lt;/span&gt;
&lt;/div&gt;
&lt;div class="flow-row"&gt;
&lt;strong&gt;证明工具&lt;/strong&gt;
&lt;span&gt;普通归纳、完全归纳、字典序归纳，都是为了证明“无限多对象都满足某性质”。&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/aside&gt;
&lt;/div&gt;
&lt;/header&gt;
&lt;main&gt;
&lt;section id="ordered" class="wrap"&gt;
&lt;div class="section-head"&gt;
&lt;div&gt;
&lt;h2&gt;2.2 有序集：先理解关系的四个性质&lt;/h2&gt;
&lt;p class="hint"&gt;二元关系可以先粗略想成“两个元素之间画箭头”。这些性质描述箭头应该满足什么规律。&lt;/p&gt;
&lt;/div&gt;
&lt;span class="pill"&gt;点击卡片可高亮&lt;/span&gt;
&lt;/div&gt;
&lt;div class="grid concept-grid"&gt;
&lt;article class="card" tabindex="0"&gt;
&lt;h3&gt;自反 Reflexive &lt;span class="tag"&gt;自己到自己&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;每个元素都和自身相关。&lt;/p&gt;
&lt;div class="formula"&gt;对所有 s ∈ S，都有 s R s&lt;/div&gt;
&lt;/article&gt;
&lt;article class="card" tabindex="0"&gt;
&lt;h3&gt;对称 Symmetric &lt;span class="tag"&gt;双向&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;如果 s 能到 t，那么 t 也能到 s。&lt;/p&gt;
&lt;div class="formula"&gt;s R t ⇒ t R s&lt;/div&gt;
&lt;/article&gt;
&lt;article class="card" tabindex="0"&gt;
&lt;h3&gt;传递 Transitive &lt;span class="tag"&gt;可接力&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;如果 s 到 t，t 到 u，那么 s 也到 u。&lt;/p&gt;
&lt;div class="formula"&gt;s R t ∧ t R u ⇒ s R u&lt;/div&gt;
&lt;/article&gt;
&lt;article class="card" tabindex="0"&gt;
&lt;h3&gt;反对称 Antisymmetric &lt;span class="tag"&gt;互相小于只能相等&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;如果 s 到 t 且 t 到 s，那么它们其实是同一个元素。&lt;/p&gt;
&lt;div class="formula"&gt;s R t ∧ t R s ⇒ s = t&lt;/div&gt;
&lt;/article&gt;
&lt;/div&gt;
&lt;section&gt;
&lt;table class="compare" aria-label="预序、偏序、全序、等价关系对比"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;概念&lt;/th&gt;
&lt;th&gt;需要哪些性质&lt;/th&gt;
&lt;th&gt;直觉&lt;/th&gt;
&lt;th&gt;典型想法&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;预序 preorder&lt;/td&gt;
&lt;td&gt;自反 + 传递&lt;/td&gt;
&lt;td&gt;可以比较“可达性”或“弱顺序”，允许两个不同元素互相可达。&lt;/td&gt;
&lt;td&gt;s ≤ t 表示 s 不超过 t；s &amp;lt; t 表示 s ≤ t 且 s ≠ t。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;偏序 partial order&lt;/td&gt;
&lt;td&gt;预序 + 反对称&lt;/td&gt;
&lt;td&gt;真正有“高低层级”的顺序，但不是任意两点都能比较。&lt;/td&gt;
&lt;td&gt;集合包含关系 ⊆ 是偏序。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;全序 total order&lt;/td&gt;
&lt;td&gt;偏序 + 任意两个元素可比较&lt;/td&gt;
&lt;td&gt;所有元素都能排成一条线。&lt;/td&gt;
&lt;td&gt;自然数上的 ≤ 是全序。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;等价关系 equivalence&lt;/td&gt;
&lt;td&gt;自反 + 对称 + 传递&lt;/td&gt;
&lt;td&gt;把元素分成若干“同类”。&lt;/td&gt;
&lt;td&gt;“模 n 同余”是一种等价关系。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/section&gt;
&lt;section class="split"&gt;
&lt;div class="callout green"&gt;
&lt;h3&gt;Join：最小上界&lt;/h3&gt;
&lt;p&gt;j 是 s 和 t 的 join，意思是 j 同时在 s、t 上面，而且在所有共同上界里，j 是最低的那个。&lt;/p&gt;
&lt;div class="formula"&gt;s ≤ j ∧ t ≤ j，并且任意共同上界 k 都满足 j ≤ k&lt;/div&gt;
&lt;/div&gt;
&lt;div class="callout amber"&gt;
&lt;h3&gt;Meet：最大下界&lt;/h3&gt;
&lt;p&gt;m 是 s 和 t 的 meet，意思是 m 同时在 s、t 下面，而且在所有共同下界里，m 是最高的那个。&lt;/p&gt;
&lt;div class="formula"&gt;m ≤ s ∧ m ≤ t，并且任意共同下界 n 都满足 n ≤ m&lt;/div&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="sequences" class="wrap"&gt;
&lt;div class="section-head"&gt;
&lt;div&gt;
&lt;h2&gt;2.3 序列：逗号既能加元素，也能拼序列&lt;/h2&gt;
&lt;p class="hint"&gt;TAPL 这里的约定很轻量：序列就是用逗号隔开的元素列表，空序列写成 bullet 或留空。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="split"&gt;
&lt;article class="card"&gt;
&lt;h3&gt;例子复盘&lt;/h3&gt;
&lt;p&gt;设 a 是序列 3, 2, 1；b 是序列 5, 6。&lt;/p&gt;
&lt;div class="sequence-demo" aria-label="序列例子"&gt;
&lt;div class="seq"&gt;&lt;span class="operator"&gt;0, a =&lt;/span&gt;&lt;span class="chip"&gt;0&lt;/span&gt;&lt;span class="chip"&gt;3&lt;/span&gt;&lt;span class="chip"&gt;2&lt;/span&gt;&lt;span class="chip"&gt;1&lt;/span&gt;&lt;/div&gt;
&lt;div class="seq"&gt;&lt;span class="operator"&gt;a, 0 =&lt;/span&gt;&lt;span class="chip"&gt;3&lt;/span&gt;&lt;span class="chip"&gt;2&lt;/span&gt;&lt;span class="chip"&gt;1&lt;/span&gt;&lt;span class="chip"&gt;0&lt;/span&gt;&lt;/div&gt;
&lt;div class="seq"&gt;&lt;span class="operator"&gt;b, a =&lt;/span&gt;&lt;span class="chip"&gt;5&lt;/span&gt;&lt;span class="chip"&gt;6&lt;/span&gt;&lt;span class="chip"&gt;3&lt;/span&gt;&lt;span class="chip"&gt;2&lt;/span&gt;&lt;span class="chip"&gt;1&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/article&gt;
&lt;article class="card"&gt;
&lt;h3&gt;需要记住的约定&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1..n&lt;/strong&gt; 表示从 1 到 n 的序列，中间只有两个点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;|a|&lt;/strong&gt; 表示序列 a 的长度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;permutation&lt;/strong&gt; 表示两个序列包含完全相同的元素，只是顺序可能不同。&lt;/p&gt;
&lt;p&gt;逗号同时表示 cons 和 append；只要不讨论“序列的序列”，通常不会混淆。&lt;/p&gt;
&lt;/article&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="induction" class="wrap"&gt;
&lt;div class="section-head"&gt;
&lt;div&gt;
&lt;h2&gt;2.4 归纳法：证明无限对象的工具箱&lt;/h2&gt;
&lt;p class="hint"&gt;归纳法的核心感觉是：只要能从“更小情况已经成立”推出“当前情况成立”，就能覆盖所有情况。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="grid"&gt;
&lt;article class="card"&gt;
&lt;h3&gt;普通归纳 &lt;span class="tag"&gt;一步接一步&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;证明 P(0)，再证明 P(i) 能推出 P(i+1)，于是所有自然数 n 都满足 P(n)。&lt;/p&gt;
&lt;div class="formula"&gt;P(0) ∧ ∀i. P(i) ⇒ P(i+1) ⟹ ∀n. P(n)&lt;/div&gt;
&lt;/article&gt;
&lt;article class="card"&gt;
&lt;h3&gt;完全归纳 &lt;span class="tag"&gt;依赖所有更小项&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;证明每个 n 时，可以假设所有 i &amp;lt; n 的 P(i) 都已经成立。&lt;/p&gt;
&lt;div class="formula"&gt;若 ∀n. (∀i&amp;lt;n. P(i)) ⇒ P(n)，则 ∀n. P(n)&lt;/div&gt;
&lt;/article&gt;
&lt;/div&gt;
&lt;/section&gt;
&lt;section id="lexicographic" class="wrap"&gt;
&lt;div class="section-head"&gt;
&lt;div&gt;
&lt;h2&gt;字典序归纳：二维版本的“更小情况”&lt;/h2&gt;
&lt;p class="hint"&gt;你问“这个公理应该怎么理解”，关键就在于把 (m,n) 想成二维表格里的一个格子。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="split"&gt;
&lt;article class="induction-board" aria-label="字典序归纳二维表格"&gt;
&lt;h3&gt;正在证明 P(2,3)&lt;/h3&gt;
&lt;p&gt;蓝色格子是字典序上已经可以假设成立的情况；黄色格子是当前要证明的情况。&lt;/p&gt;
&lt;div class="board-grid"&gt;
&lt;div class="cell done"&gt;(0,0)&lt;/div&gt;
&lt;div class="cell done"&gt;(0,1)&lt;/div&gt;
&lt;div class="cell done"&gt;(0,2)&lt;/div&gt;
&lt;div class="cell done"&gt;(0,3)&lt;/div&gt;
&lt;div class="cell done"&gt;(0,4)&lt;/div&gt;
&lt;div class="cell done"&gt;(0,5)&lt;/div&gt;
&lt;div class="cell done"&gt;(1,0)&lt;/div&gt;
&lt;div class="cell done"&gt;(1,1)&lt;/div&gt;
&lt;div class="cell done"&gt;(1,2)&lt;/div&gt;
&lt;div class="cell done"&gt;(1,3)&lt;/div&gt;
&lt;div class="cell done"&gt;(1,4)&lt;/div&gt;
&lt;div class="cell done"&gt;(1,5)&lt;/div&gt;
&lt;div class="cell done"&gt;(2,0)&lt;/div&gt;
&lt;div class="cell done"&gt;(2,1)&lt;/div&gt;
&lt;div class="cell done"&gt;(2,2)&lt;/div&gt;
&lt;div class="cell current"&gt;(2,3)&lt;/div&gt;
&lt;div class="cell"&gt;(2,4)&lt;/div&gt;
&lt;div class="cell"&gt;(2,5)&lt;/div&gt;
&lt;div class="cell"&gt;(3,0)&lt;/div&gt;
&lt;div class="cell"&gt;(3,1)&lt;/div&gt;
&lt;div class="cell"&gt;(3,2)&lt;/div&gt;
&lt;div class="cell"&gt;(3,3)&lt;/div&gt;
&lt;div class="cell"&gt;(3,4)&lt;/div&gt;
&lt;div class="cell"&gt;(3,5)&lt;/div&gt;
&lt;/div&gt;
&lt;div class="legend"&gt;
&lt;span&gt;蓝色：m' &amp;lt; m 的所有行，或同一行 n' &amp;lt; n&lt;/span&gt;
&lt;span&gt;黄色：当前目标&lt;/span&gt;
&lt;/div&gt;
&lt;/article&gt;
&lt;div class="callout blue"&gt;
&lt;h3&gt;一句话理解&lt;/h3&gt;
&lt;p&gt;对一对自然数 (m,n) 做归纳：如果每一格只依赖它之前所有“更小的格子”，那整张无限表格上的所有格子都成立。&lt;/p&gt;
&lt;div class="formula"&gt;(m',n') &amp;lt; (m,n) 当且仅当 m' &amp;lt; m，或 m'=m 且 n'&amp;lt;n&lt;/div&gt;
&lt;p&gt;这就是嵌套归纳的抽象写法：外层对 m 归纳，固定 m 后内层再对 n 归纳。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;section class="memory"&gt;
&lt;article class="card"&gt;
&lt;h3&gt;普通归纳像一条线&lt;/h3&gt;
&lt;p&gt;0, 1, 2, 3... 每次只往前走一步。&lt;/p&gt;
&lt;/article&gt;
&lt;article class="card"&gt;
&lt;h3&gt;完全归纳像看左边全部&lt;/h3&gt;
&lt;p&gt;证明 n 时，左边所有小于 n 的点都可以作为前提。&lt;/p&gt;
&lt;/article&gt;
&lt;article class="card"&gt;
&lt;h3&gt;字典序归纳像读表格&lt;/h3&gt;
&lt;p&gt;先读完上一行，再读当前行左边的格子，然后证明当前格子。&lt;/p&gt;
&lt;/article&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="closure" class="wrap"&gt;
&lt;div class="section-head"&gt;
&lt;div&gt;
&lt;h2&gt;闭包：给关系补上缺失性质&lt;/h2&gt;
&lt;p class="hint"&gt;闭包的关键词是“最小”。不是随便扩展，而是在满足某性质的前提下，尽量少加东西。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="grid"&gt;
&lt;article class="card"&gt;
&lt;h3&gt;自反闭包&lt;/h3&gt;
&lt;p&gt;给 R 补上所有 (s,s)，让每个元素都和自己相关。&lt;/p&gt;
&lt;div class="formula"&gt;R' = R ∪ {(s,s) | s ∈ S}&lt;/div&gt;
&lt;/article&gt;
&lt;article class="card"&gt;
&lt;h3&gt;传递闭包&lt;/h3&gt;
&lt;p&gt;给 R 补上所有通过多步能到达的关系，通常记作 R+。&lt;/p&gt;
&lt;div class="formula"&gt;若 a R b 且 b R c，就需要补出 a R c&lt;/div&gt;
&lt;/article&gt;
&lt;article class="card"&gt;
&lt;h3&gt;自反且传递闭包&lt;/h3&gt;
&lt;p&gt;同时补自反性和传递性，通常记作 R*。&lt;/p&gt;
&lt;div class="formula"&gt;R* 包含“走 0 步或多步”的可达关系&lt;/div&gt;
&lt;/article&gt;
&lt;article class="card"&gt;
&lt;h3&gt;最小的含义&lt;/h3&gt;
&lt;p&gt;如果另一个关系也包含 R 且满足目标性质，那么闭包一定包含在那个关系里面。&lt;/p&gt;
&lt;div class="formula"&gt;若 R'' 也满足要求，则 R' ⊆ R''&lt;/div&gt;
&lt;/article&gt;
&lt;/div&gt;
&lt;section&gt;
&lt;details open&gt;
&lt;summary&gt;练习 2.2.6：为什么 R ∪ {(s,s) | s ∈ S} 是 R 的自反闭包？&lt;/summary&gt;
&lt;div class="steps"&gt;
&lt;div class="step"&gt;&lt;strong&gt;先证明它包含 R。&lt;/strong&gt; 因为 R' 是 R 和另一组有序对的并集，所以 R ⊆ R'。&lt;/div&gt;
&lt;div class="step"&gt;&lt;strong&gt;再证明它自反。&lt;/strong&gt; 对任意 s ∈ S，(s,s) 都被显式加入到 R' 里，所以 R' 是自反的。&lt;/div&gt;
&lt;div class="step"&gt;&lt;strong&gt;最后证明它最小。&lt;/strong&gt; 任取一个自反关系 R''，并且 R ⊆ R''。因为 R'' 自反，所以所有 (s,s) 都在 R'' 里；又因为 R 中的对也都在 R'' 里，所以 R' 的所有元素都在 R'' 里，即 R' ⊆ R''。&lt;/div&gt;
&lt;div class="step"&gt;&lt;strong&gt;结论。&lt;/strong&gt; R' 既包含 R，又自反，并且在所有满足这两个条件的关系里最小，所以它就是 R 的自反闭包。&lt;/div&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;/main&gt;
&lt;footer&gt;
&lt;div class="wrap"&gt;
&lt;strong&gt;复习路线：&lt;/strong&gt;先背关系性质，再区分 preorder / partial order / total order / equivalence；然后记住 join 和 meet 的“共同上界/下界里的最小/最大”；最后把归纳法都看成“用更小情况推出当前情况”。
&lt;/div&gt;
&lt;/footer&gt;
&lt;script&gt;
const cards = document.querySelectorAll(".concept-grid .card");
cards.forEach((card) =&gt; {
card.addEventListener("click", () =&gt; {
cards.forEach((item) =&gt; item.classList.remove("active-card"));
card.classList.add("active-card");
});
card.addEventListener("keydown", (event) =&gt; {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
card.click();
}
});
});
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</description></item></channel></rss>