- 文档
- 教程
【免费下载链接】learnxinyminutes-docs
Code documentation written as code! How novel and totally my idea!
本文基于开源仓库 learnxinyminutes-docs 中的西班牙语教程 es/lambda-calculus.md(其英文原版为 lambda-calculus.md,本仓库将该主题归类于 "Algorithms & Data Structures")系统展开。λ 演算(Cálculo Lambda)由 [Alonzo Church] 于 20 世纪 30 年代提出,被认为是"世界上最小的编程语言":它没有数字、字符串、布尔值或任何非函数数据类型,却足以表示任何图灵机。读完本文,你将掌握 λ 演算的三种基本构造、β-归约求值、丘奇编码(Church numerals)的布尔与自然数表示,以及如何把表达式逐步压缩为更极简的 SKI、SK 与 Iota 组合子演算。
一、λ 演算的三种基本元素
λ 演算全部由三种元素构成:变量(variables)、函数(functions)和应用(applications)。下表完整对应原文档的语法定义:
| 名称(Nombre) | 语法(Sintaxis) | 示例(Ejemplo) | 解释(Explicación) |
|---|---|---|---|
| 变量(Variable) | <nombre>/<name> | x | 一个名为 "x" 的变量 |
| 函数(Función) | λ<parámetro>.<cuerpo>/λ<parameters>.<body> | λx.x | 以 "x" 为参数、以 "x" 为函数体的函数 |
| 应用(Aplicación) | <función><variable o función>/<function><variable or function> | (λx.x)a | 以参数 "a" 调用函数 "λx.x" |
最基本的函数是恒等函数(función de identidad):λx.x,它等价于普通数学记号f(x) = x。其中第一个 "x" 是函数参数,第二个 "x" 是函数体。
说明:在本仓库中,λ 演算教程以多语言形式维护,除西班牙语 es/lambda-calculus.md 与英文原版 lambda-calculus.md 外,还提供了 中文版、法语版、葡萄牙语版 等翻译,各版本核心内容保持一致,便于对照阅读。
二、自由变量(Libres)与约束变量(Enlazadas)
区分变量是否被"绑定"是理解 λ 演算的第一步:
- 在函数
λx.x中,"x" 被称为约束变量(variable enlazada),因为它同时出现在函数体与参数位置,参数声明约束了函数体内的同名出现。 - 在
λx.y中,"y" 被称为自由变量(variable libre),因为它从未被预先声明,游离于任何抽象之外。
从实现角度看,这一区分正是所有词法作用域语言的核心机制:约束变量对应"局部变量",自由变量对应"必须由外部环境提供"的名称。后续 β-归约的替换规则也依赖于这一概念。
三、求值:β-归约(β-Reduction)
求值通过β-归约完成,其本质就是词法作用域内的替换(sustitución de ámbito léxico):求值表达式(λx.x)a时,把函数体中所有出现的 "x" 替换为 "a"。
基础归约示例:
(λx.x)a归约得到:a(λx.y)a归约得到:y(因为 "y" 是自由变量,替换不触及它)
还可以构造高阶函数(funciones de orden superior)——函数的返回值仍是函数:
(λx.(λy.x))a归约得到:λy.a
柯里化(Currificación / Currying)
传统 λ 演算只支持单参数函数,但通过柯里化技术可以表达多参数函数:把f(x, y, z)改写为逐个接收参数、逐个返回函数的形式。
(λx.λy.λz.xyz)等价于f(x, y, z) = ((x y) z)
有时λxy.<cuerpo>(即λx.λy.<cuerpo>)的缩写写法与完整嵌套形式互换使用,二者语义完全一致。现代函数式语言(如 Haskell 等)中"函数天然柯里化"的设计理念正是源于此处。
一个关键认知
必须强调:传统 λ 演算没有数字、字符或任何非函数数据类型。下面即将看到的"布尔值"与"自然数"全部是函数编码的产物,而非内建类型。
四、布尔逻辑:用函数表示真与假
λ 演算中没有 "Verdadero"/"Falso",甚至没有 1 或 0。取而代之的是两个特殊的二参数函数:
T表示为:λx.λy.x(选择第一个参数)F表示为:λx.λy.y(选择第二个参数)
首先定义 "if" 函数IF:若b为真则返回t,若b为假则返回f。
IF等价于:λb.λt.λf.b t f
借助IF可以定义基本布尔逻辑运算符:
a AND b等价于:λab.IF a b Fa OR b等价于:λab.IF a T bNOT a等价于:λa.IF a F T
注:
IF a b c本质上表示IF((a b) c),即IF依次应用于三个参数;由于应用是左结合的,b t f即(b t) f——"把b当作选择器,喂给它t和f"。
验证一下:AND T F展开为IF T F F = T F F,而T F F = (λx.λy.x) F F = F,结果正确。可见布尔值本质上是"选择函数"。
五、自然数:丘奇编码(Números de Church)
λ 演算中没有数字,但可以用丘奇数(Númeral de Church)把自然数编码为函数。其思想是:数字n表示"把函数f应用n次",即n = λf.fn。因此:
0 = λf.λx.x1 = λf.λx.f x2 = λf.λx.f(f x)3 = λf.λx.f(f(f x))
后继函数(función sucesora)
要让丘奇数自增S(n) = n + 1,定义:
S = λn.λf.λx.f((n f) x)
其含义是:给定丘奇数n与函数f,先对x应用n f(即n次),再额外应用一次f,从而得到n+1次应用。
加法(AGREGAR / ADD)
借助后继函数可以定义加法:
AGREGAR = λab.(a S)b
即:对a反复施加后继函数b次,得到a + b。(注:英文原版写作ADD = λab.(a S)b,西班牙语版存在笔误(a S)n,应以(a S)b为准,中文版 同样使用正确形式。)
挑战(Desafío):尝试自己定义乘法函数!提示:乘法
a × b可以理解为"把b复制a份并叠加",一个常见答案是MULT = λab.λf.a (b f)。
六、变得更小:SKI、SK 与 Iota 组合子演算
原文档在讲完丘奇数后,进一步压缩 λ 演算本身,展示如何用更少的原语表达一切。
SKI 组合子演算(Cálculo del combinador SKI)
设 S、K、I 为如下函数:
I x = x(恒等)K x y = x(常函数:丢弃第二个参数)S x y z = x z (y z)(分配/替换规则)
可以把 λ 演算中的任意表达式转换为 SKI 组合子表达式,只需三条转换规则:
λx.x = Iλx.c = Kc(前提:x未在c中自由出现)λx.(y z) = S (λx.y) (λx.z)
以丘奇数 2 为例演示完整推导(2 = λf.λx.f(f x)):
先处理内层λx.f(f x):
λx.f(f x) = S (λx.f) (λx.(f x)) (规则 3) = S (K f) (S (λx.f) (λx.x)) (规则 2、3) = S (K f) (S (K f) I) (规则 2、1)于是:
2 = λf.λx.f(f x) = λf.(S (K f) (S (K f) I)) = λf.((S (K f)) (S (K f) I)) = S (λf.(S (K f))) (λf.(S (K f) I)) (规则 3)对第一个参数λf.(S (K f))继续转换:
λf.(S (K f)) = S (λf.S) (λf.(K f)) (规则 3) = S (K S) (S (λf.K) (λf.f)) (规则 2、3) = S (K S) (S (K K) I) (规则 2、3)对第二个参数λf.(S (K f) I):
λf.(S (K f) I) = λf.((S (K f)) I) = S (λf.(S (K f))) (λf.I) (规则 3) = S (S (λf.S) (λf.(K f))) (K I) (规则 2、3) = S (S (K S) (S (λf.K) (λf.f))) (K I) (规则 1、3) = S (S (K S) (S (K K) I)) (K I) (规则 1、2)合并两部分:
2 = S (λf.(S (K f))) (λf.(S (K f) I)) = S (S (K S) (S (K K) I)) (S (S (K S) (S (K K) I)) (K I))若继续展开这个最终表达式,会再次得到与丘奇数 2 等价的表达式——转换是保语义的,这正是组合子演算作为 λ 演算等价形式的价值。
SK 组合子演算
SKI 还可以继续精简。注意到I = SKK(因为SKK x = K x (K x) = x),因此可以用SKK替换所有I,去掉 I 组合子,得到只有 S 与 K 两个原语的SK 组合子演算。
Iota 组合子
SK 演算仍非最简。定义单参数组合子 ι:
ι = λf.((f S) K)可以仅用 ι 重构出 I、K、S:
I = ιι K = ι(ιI) = ι(ι(ιι)) S = ι(K) = ι(ι(ι(ιι)))至此,整个 λ 演算的能力被压缩进单一符号 ι——"最小"的追求走到了逻辑极限。这一系列从 SKI → SK → Iota 的压缩链条,直观展示了组合子逻辑(combinatory logic)如何用极少的原语保持图灵完备性。
七、本仓库中的文档组织与质量保障
learnxinyminutes-docs 仓库以"把文档写成代码、随代码讲解"的方式维护这些教程。关于 λ 演算主题,仓库内同时维护着英文原版 lambda-calculus.md(frontmatter 中声明category: Algorithms & Data Structures)以及 es/lambda-calculus.md、zh-cn/lambda-calculus.md、fr/lambda-calculus.md、pt-br/lambda-calculus.md 等多语言版本;各版本共用同一套作者署名,翻译者单独记录于translators字段。
仓库为每篇文章提供了规范化的 frontmatter 与风格约束:
- CONTRIBUTING.md 要求代码行宽不超过 80 字符、优先用代码示例而非长篇论述、全篇使用 UTF-8 编码,并定义了
name、contributors、category、filename、translators等元数据字段;非英文文章会继承英文版的 frontmatter 值。 - lint/frontmatter.py 中的
extract_yaml_frontmatter负责从 Markdown 文件头部提取---包裹的 YAML 元数据,validate_yaml_keys则校验文档只允许出现规定的键,确保所有语种文章的元数据结构一致、可被站点生成器正确消费。
如果你想在本地通读全文,直接查看 es/lambda-calculus.md(西班牙语)或 lambda-calculus.md(英文)即可;对照 中文版 可以快速消除语言障碍。
八、进一步阅读建议
原文档末尾给出了一系列进阶资料方向,这里整理为纯文字指引(不附外部链接):
- 《A Tutorial Introduction to the Lambda Calculus》(λ 演算入门教程,学术向经典 PDF 讲义);
- 康奈尔大学 CS 3110/CS 312 关于 λ 演算的复习讲义;
- 维基百科的 "Lambda Calculus" 词条(含 β-归约、α-等价等严格定义);
- 维基百科的 "SKI combinator calculus" 词条;
- 维基百科的 "Iota and Jot" 词条(单一原语的极简语言家族)。
建议按顺序阅读:先吃透本文的三大元素与 β-归约,再用丘奇编码动手实现加法与乘法(完成文中的挑战),最后沿着 SKI → SK → Iota 的推导亲手走一遍,即可对"可计算性理论的最小区块"建立完整的直觉。
- 文档
- 教程
【免费下载链接】learnxinyminutes-docs
Code documentation written as code! How novel and totally my idea!
相关推荐
Learn X in Y Minutes 之 Go 语言实战指南:从语法骨架到并发与 Web 编程
Learn X in Y Minutes 之 Go 语言实战指南:从语法骨架到并发与 Web 编程 本篇指南以 learnxinyminutes docs 仓库
文档教程Jest Timer Mocks 完全指南:用假定时器精确控制测试时间
Jest Timer Mocks 完全指南:用假定时器精确控制测试时间 导读 在 Jest 测试中, setTimeout 、 setInterval 等原生定
文档教程Learn X in Y Minutes 之 SmallBASIC:从语法速览到图形与 JSON 实战
Learn X in Y Minutes 之 SmallBASIC:从语法速览到图形与 JSON 实战 本指南基于 learnxinyminutes docs
文档教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考