TCS: Programming in Lambda Calculus

Programming in Lambda Calculus

Reduction and Normal Forms

A β\beta-redex is a subterm of the form (λx.M)N(\lambda x.M)N. Contracting it replaces that subterm by M[N/x]M[N/x], using capture-avoiding substitution

The one-step relation →β\to_\beta permits contraction anywhere inside a term

M→βM′MN→βM′NN→βN′MN→βMN′M→βM′λx.M→βλx.M′\frac{M\to_\beta M'}{MN\to_\beta M'N}\qquad\frac{N\to_\beta N'}{MN\to_\beta MN'}\qquad\frac{M\to_\beta M'}{\lambda x.M\to_\beta\lambda x.M'}

Write →β∗\to_\beta^* for zero or more reduction steps, and =β=_\beta for the equivalence relation generated by reduction

For example, SKK\mathbf S\mathbf K\mathbf K implements identity

SKK→β∗λz.Kz(Kz)→β∗λz.z=I\mathbf S\mathbf K\mathbf K \to_\beta^*\lambda z.\mathbf Kz(\mathbf Kz) \to_\beta^*\lambda z.z =\mathbf I

Three Termination Properties

  • A term is in normal form when it contains no β\beta-redex
  • A term is normalizable when at least one reduction sequence reaches a normal form
  • A term is strongly normalizable when every reduction sequence terminates

The distinction is visible in (λx.I)Ω(\lambda x.\mathbf I)\Omega. Contracting the outer redex immediately produces I\mathbf I, but repeatedly reducing the argument Ω\Omega gives an infinite sequence

Normal-order reduction contracts the leftmost outermost redex, including redexes under abstractions when computing a full normal form. If a term has a normal form, this strategy eventually finds it

This theorem explains why evaluating an unused argument first can lose termination. Programming-language call-by-name is related to normal order, but usually stops before reducing beneath an unapplied abstraction

Church-Rosser Theorem

Different choices of redex can produce different intermediate terms. Confluence says that these choices remain compatible

If M→β∗PM\to_\beta^*P and M→β∗QM\to_\beta^*Q, then some RR satisfies

P→β∗RQ→β∗RP\to_\beta^*R\qquadQ\to_\beta^*R

Consequently, a term has at most one β\beta-normal form up to α\alpha-equivalence

Confluence does not assert termination. The term Ω\Omega still has an infinite reduction sequence and no normal form

One-step reduction itself need not have the diamond property. Contracting a redex may duplicate an argument, after which reducing its two copies requires two steps rather than one

Parallel Reduction

The proof introduces ⇒\Rightarrow, which contracts several redexes together

x⇒xM⇒M′λx.M⇒λx.M′\frac{}{x\Rightarrow x} \qquad \frac{M\Rightarrow M'}{\lambda x.M\Rightarrow\lambda x.M'}

M⇒M′N⇒N′MN⇒M′N′M⇒M′N⇒N′(λx.M)N⇒M′[N′/x]\frac{M\Rightarrow M'\quad N\Rightarrow N'}{MN\Rightarrow M'N'} \qquad \frac{M\Rightarrow M'\quad N\Rightarrow N'} {(\lambda x.M)N\Rightarrow M'[N'/x]}

Two ingredients make the argument work

  1. Substitution respects parallel reduction: if M⇒M′M\Rightarrow M' and N⇒N′N\Rightarrow N', then M[N/x]⇒M′[N′/x]M[N/x]\Rightarrow M'[N'/x]
  2. Parallel reduction has the diamond property, proved by structural induction and a case analysis of the application rules

The substitution lemma handles the case where one derivation contracts an outer redex while the other reduces its body or argument. The induction hypothesis provides compatible reducts of the subterms

Finally,

→β ⊆ ⇒ ⊆ →β∗\to_\beta\ \subseteq\ \Rightarrow\ \subseteq\ \to_\beta^*

Thus the two relations have the same reflexive transitive closure, and the diamond property of parallel reduction yields confluence of β\beta-reduction

As an application, zz and λu.zu\lambda u.zu are distinct β\beta-normal forms when u≠zu\ne z. They are not β\beta-equal, although the η\eta rule identifies them. Therefore η\eta is an additional equation

Encoding Booleans

A Boolean can be represented as a function choosing between two arguments

T=λab.aF=λab.bif=λbxy.bxy\mathbf T=\lambda ab.a\qquad\mathbf F=\lambda ab.b\qquad\mathbf{if}=\lambda bxy.bxy

Then if T M N→β∗M\mathbf{if}\,\mathbf T\,M\,N\to_\beta^*M and if F M N→β∗N\mathbf{if}\,\mathbf F\,M\,N\to_\beta^*N. The selector itself implements branching

Boolean operators can be defined without new syntax

not=λb.bFTand=λab.abFor=λab.aTb\begin{aligned} \mathbf{not}&=\lambda b.b\mathbf F\mathbf T\\ \mathbf{and}&=\lambda ab.ab\mathbf F\\ \mathbf{or}&=\lambda ab.a\mathbf T b \end{aligned}

For instance, and F N\mathbf{and}\,\mathbf F\,N selects F\mathbf F without needing to evaluate NN under normal order

Church Numerals

The numeral for nn applies a function nn times to an initial value

n‾=λfx.fnx\overline n=\lambda fx.f^n x

In particular,

0‾=λfx.x1‾=λfx.fx2‾=λfx.f(fx)\overline0=\lambda fx.x\qquad\overline1=\lambda fx.fx\qquad\overline2=\lambda fx.f(fx)

The same term can serve different encodings: 0‾\overline0 and F\mathbf F are α\alpha-equivalent. In the untyped calculus, the surrounding program determines the intended interpretation

Arithmetic by Iteration

succ=λnfx.f(nfx)add=λmnfx.mf(nfx)mult=λmnfx.m(nf)x\begin{aligned} \mathbf{succ}&=\lambda nfx.f(nfx)\\ \mathbf{add}&=\lambda mnfx.mf(nfx)\\ \mathbf{mult}&=\lambda mnfx.m(nf)x \end{aligned}

Successor adds one application of ff. Addition composes mm applications with nn applications. Multiplication iterates the function nfnf, which itself performs nn applications, a total of mm times

For example,

add 2‾ 3‾→β∗λfx.f(f(f(f(fx))))=5‾\mathbf{add}\,\overline2\,\overline3 \to_\beta^*\lambda fx.f(f(f(f(fx)))) =\overline5

Exponentiation reverses the order in which the numerals are applied

pow=λmnfx.nmfx\mathbf{pow}=\lambda mnfx.nmfx

On Church numerals, pow m‾ n‾→β∗mn‾\mathbf{pow}\,\overline m\,\overline n\to_\beta^*\overline{m^n}, taking m0=1m^0=1, including the convention 00=10^0=1 for this operation

Zero Test and Predecessor

A zero test starts with true and replaces it by false whenever the numeral performs an iteration

iszero=λn.n(λu.F)T\mathbf{iszero}=\lambda n.n(\lambda u.\mathbf F)\mathbf T

For predecessor, keep a pair of consecutive values. Starting from (0,0)(0,0), repeatedly update (a,b)(a,b) to (b,b+1)(b,b+1). After nn iterations the first component is max⁡(n−1,0)\max(n-1,0)

Using the pair operations developed in Lecture 3, this gives

step=λp.pair (snd p)(succ (snd p))pred=λn.fst (n step (pair 0‾ 0‾))\begin{aligned} \mathbf{step}&=\lambda p.\mathbf{pair}\,(\mathbf{snd}\,p) (\mathbf{succ}\,(\mathbf{snd}\,p))\\ \mathbf{pred}&=\lambda n.\mathbf{fst}\, (n\,\mathbf{step}\,(\mathbf{pair}\,\overline0\,\overline0)) \end{aligned}

Currying and Representation

Every abstraction binds one variable. A function of several arguments is represented by nested abstractions, so applying it to fewer arguments returns another function

add 4‾→β∗λnfx.4‾f(nfx)\mathbf{add}\,\overline4 \to_\beta^*\lambda nfx.\overline4f(nfx)

This is partial application: the resulting term adds four to its next numeral argument

More generally, a term MM represents f:Nk→Nf:\mathbb N^k\to\mathbb N when, for every input tuple,

Mn1‾⋯nk‾→β∗f(n1,…,nk)‾M\overline{n_1}\cdots\overline{n_k} \to_\beta^*\overline{f(n_1,\ldots,n_k)}

Correctness therefore connects an operation on encoded values with ordinary mathematical computation


© 2024 本网站由 renxiaodaifu 使用 Stellar主题 创建
总访问 次 | 本页访问 次
共发表 103 篇 Blog(s) · 总计 254.1k 字