☰
Learn X in Y Minutes 之 λ 演算:从三条语法规则到 SKI 与 Iota 组合子的最小编程语言指南
2026/10/8 6:55:49 网站建设 项目流程
  • 文档
  • 教程

【免费下载链接】learnxinyminutes-docs

Code documentation written as code! How novel and totally my idea!

项目地址:https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs
点击查看免费下载

本文基于开源仓库 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 F
  • a OR b等价于:λab.IF a T b
  • NOT 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.x
  • 1 = λf.λx.f x
  • 2 = λ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 组合子表达式,只需三条转换规则:

  1. λx.x = I
  2. λx.c = Kc(前提:x未在c中自由出现)
  3. λ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(英文)即可;对照 中文版 可以快速消除语言障碍。

八、进一步阅读建议

原文档末尾给出了一系列进阶资料方向,这里整理为纯文字指引(不附外部链接):

  1. 《A Tutorial Introduction to the Lambda Calculus》(λ 演算入门教程,学术向经典 PDF 讲义);
  2. 康奈尔大学 CS 3110/CS 312 关于 λ 演算的复习讲义;
  3. 维基百科的 "Lambda Calculus" 词条(含 β-归约、α-等价等严格定义);
  4. 维基百科的 "SKI combinator calculus" 词条;
  5. 维基百科的 "Iota and Jot" 词条(单一原语的极简语言家族)。

建议按顺序阅读:先吃透本文的三大元素与 β-归约,再用丘奇编码动手实现加法与乘法(完成文中的挑战),最后沿着 SKI → SK → Iota 的推导亲手走一遍,即可对"可计算性理论的最小区块"建立完整的直觉。

  • 文档
  • 教程

【免费下载链接】learnxinyminutes-docs

Code documentation written as code! How novel and totally my idea!

项目地址:https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询