Skip to content

Research note

What Happens to Currying When Beta and Eta Become Computations?

A worked path through Seely's 2-categorical lambda calculus: from one term with two beta reductions to interchange, laxity, and the adjunction between currying and uncurrying.

16 minute read

SeriesPart 2 of 2

A worked path through Seely's 2-categorical lambda calculus: from one term with two beta reductions to interchange, laxity, and the adjunction between currying and uncurrying.

Fix a type OO, a closed function f:OOf:O\Rightarrow O, and one free input y:Oy:O. Consider the term

T(y)=(λu:O.u)((λv:O.v)(fy)).T(y) = (\lambda u:O.\,u) \big((\lambda v:O.\,v)(f\,y)\big).

It contains two beta redexes. We can contract the outer one first,

T(y)β(λv.v)(fy)βfy,T(y) \Rightarrow_\beta (\lambda v.v)(f\,y) \Rightarrow_\beta f\,y,

or the inner one first,

T(y)β(λu.u)(fy)βfy.T(y) \Rightarrow_\beta (\lambda u.u)(f\,y) \Rightarrow_\beta f\,y.

Ordinary beta equality tells us that T(y)=fyT(y)=f\,y. That statement is correct, but it does not tell us that two contractions occurred, or that they can occur in either order.

Robert Seely's 1987 paper Modelling Computations: A 2-Categorical Framework asks what happens when we refuse to erase that information. His answer changes the usual roles of beta and eta. They stop being equations that justify a cartesian closed structure and become directed cells that build a two-dimensional version of it.

After reading this article, you should be able to use the term TT to explain four points:

  1. why a conversion is naturally a 2-cell;
  2. why substitution forces some reduction histories to be identified;
  3. why eta and beta become the unit and counit of an adjunction between currying and uncurrying;
  4. why EE\Rightarrow- preserves composition through a beta comparison rather than by equality.

The intended reader knows typed lambda calculus, substitution, beta and eta, and the ordinary idea of currying. Some basic category theory is helpful, but the category-theoretic notation needed for the central calculation is explained as it appears. No domain theory or 2-category theory is assumed.

1. What does equality forget?Copy link to section

Start with the smaller redex

(λu:O.u)xβx.(\lambda u:O.\,u)x \Rightarrow_\beta x.

In the usual equational theory, we quotient terms by beta conversion. The two expressions then represent the same term. In a cartesian closed category, they are interpreted by the same morphism.

This is useful when the question is extensional: do the programs have the same result? It is insufficient when the reduction itself matters. Equality retains the endpoints and discards the witness between them.

Seely's first move is simple. Keep the typed terms as arrows, but place a new kind of arrow between parallel terms:

p:(λu.u)xβx.p: (\lambda u.u)x \Rightarrow_\beta x.

The symbol pp is not another program. It is the beta conversion from one program expression to another. This gives three levels of structure:

Lambda calculusTwo-dimensional semantics
a type AAan object
a term x:Ba:Ax:B\vdash a:Aa 1-cell a:BAa:B\to A
a conversion p:abp:a\Rightarrow ba 2-cell between parallel 1-cells

The direction BAB\to A says that the term consumes one free input of type BB and produces a result of type AA. If a term has several free variables, Seely packages their context into a product. The one-input presentation therefore does not restrict the programs we can describe.

The mental model is now this: types are boundaries, terms are programs between those boundaries, and conversions are computations between programs.

2. Why are reduction arrows alone not enough?Copy link to section

Once conversions are kept, they must compose in two ways.

Chaining steps gives vertical compositionCopy link to section

The first composition is familiar. If

p:abandq:bc,p:a\Rightarrow b \qquad\text{and}\qquad q:b\Rightarrow c,

then we can run pp followed by qq:

qp:ac.q\mathbin{\cdot}p:a\Rightarrow c.

Each of the two routes from T(y)T(y) to fyf\,y is a vertical composite of two beta conversions. The target of the first step must match the source of the second.

Placing a step in a context gives horizontal compositionCopy link to section

The second composition comes from substitution. Return to the two open terms

a(x)=(λu.u)x,b(x)=x,a(x)=(\lambda u.u)x, \qquad b(x)=x,

and their beta conversion p:abp:a\Rightarrow b. Now define

d(y)=(λv.v)(fy),e(y)=fy,d(y)=(\lambda v.v)(f\,y), \qquad e(y)=f\,y,

with the inner conversion r:der:d\Rightarrow e.

Substituting d(y)d(y) for xx in a(x)a(x) produces the running term:

a[d/x]=(λu.u)((λv.v)(fy))=T(y).a[d/x] = (\lambda u.u)((\lambda v.v)(f\,y)) = T(y).

The conversion rr can also be placed inside the context (λu.u)[](\lambda u.u)[-]:

(λu.u)d(λu.u)e.(\lambda u.u)d \Rightarrow (\lambda u.u)e.

This is substitution acting on a computation. In 2-category language it is a special case of horizontal composition. In general, from

p:ab:BAandr:de:CB,p:a\Rightarrow b:B\to A \qquad\text{and}\qquad r:d\Rightarrow e:C\to B,

substitution constructs

pr:a[d/x]b[e/x].p*r: a[d/x] \Rightarrow b[e/x].

The important point is computational: a valid local conversion remains valid when a larger term uses it.

3. Why must the two paths be identified?Copy link to section

We can now label every step in the two reductions of TT.

The outer-first route is

a[d/x] p[d/x] b[d/x]contract the outer redex, b[r] b[e/x]then contract the inner redex.\begin{aligned} a[d/x] &\xRightarrow{\ p[d/x]\ } b[d/x] &&\text{contract the outer redex},\\ &\xRightarrow{\ b[r]\ } b[e/x] &&\text{then contract the inner redex}. \end{aligned}

The inner-first route is

a[d/x] a[r] a[e/x]move the inner step through the context, p[e/x] b[e/x]then contract the outer redex.\begin{aligned} a[d/x] &\xRightarrow{\ a[r]\ } a[e/x] &&\text{move the inner step through the context},\\ &\xRightarrow{\ p[e/x]\ } b[e/x] &&\text{then contract the outer redex}. \end{aligned}

Both routes start at T(y)T(y) and end at fyf\,y. More is true: each route applies the same outer conversion and the same substituted conversion, only in the opposite order.

Here p[d/x]p[d/x] means that the term dd is substituted into both the source and target of the cell pp. The notation a[r]a[r] means that the cell rr is placed inside the term context a[]a[-]; b[r]b[r] and p[e/x]p[e/x] are read in the same way. The four labels therefore name ordinary substitution operations, now applied to conversions as well as terms.

a[d/x] p[d/x] b[d/x]a[r]b[r]a[e/x] p[e/x] b[e/x]\begin{array}{ccc} a[d/x] &\xRightarrow{\ p[d/x]\ }& b[d/x]\\ {\scriptstyle a[r]}\Big\downarrow && \Big\downarrow{\scriptstyle b[r]}\\ a[e/x] &\xRightarrow{\ p[e/x]\ }& b[e/x] \end{array}

Figure 1. Interchange identifies the outer-first and inner-first routes. The figure answers which scheduling distinction Seely's strict 2-category chooses not to retain.

For composition of terms to act functorially on conversions, the square must commute. Seely therefore imposes the equation

b[r]p[d/x]=p[e/x]a[r].b[r]\mathbin{\cdot}p[d/x] = p[e/x]\mathbin{\cdot}a[r].

This is the interchange law in the concrete language of substitution. The common 2-cell is the horizontal composite prp*r.

A common misconception: 2-cells are raw execution tracesCopy link to section

They are not raw traces in Seely's construction. The two sequences above look different as schedules, but the 2-category identifies them. More equations are added later for naturality and coherence.

Seely's model therefore sits between two extremes:

  • ordinary equational semantics erases every conversion between equal terms;
  • a raw trace model distinguishes every sequence of steps;
  • LAMBDA keeps directed conversions, then quotients some sequences so that substitution is compositional.

That middle position is the main conceptual obstacle in the paper. Replacing an equality by an arrow is only the beginning. One must also decide which arrows count as the same computation.

4. What structure have we built?Copy link to section

Seely calls the resulting 2-category LAMBDA. Starting from primitive types, its types are closed under products and function types:

A&B,AB.A\mathbin{\&}B, \qquad A\Rightarrow B.

Its terms use pairing, projections, lambda abstraction, and application. The function-type conversions are directed:

(λx:A.m)nβm[n/x],(\lambda x:A.\,m)n \Rightarrow_\beta m[n/x], cηλx:A.c(x)(x not free in c).c \Rightarrow_\eta \lambda x:A.\,c(x) \qquad (x\text{ not free in }c).

The eta rule may look reversed. Many presentations use eta contraction, λx.c(x)c\lambda x.c(x)\Rightarrow c. Seely initially chooses eta expansion because the direction will supply the unit of the adjunction in Section 5.

The rest of the construction is compact:

  • objects are types;
  • 1-cells are one-input typed terms;
  • 2-cells are directed conversions modulo the equations needed for the 2-category laws;
  • 1-cell composition is substitution;
  • vertical composition chains conversions;
  • horizontal composition substitutes conversions.

One technical convention will matter below. Seely treats alpha conversion as identity, and he collapses the product beta and eta conversions to identities so that the paper can concentrate on function types. Associativity of 1-cell composition is inherited from typed substitution. The construction therefore does not promote every lambda-calculus equation to a nontrivial 2-cell.

5. What becomes of currying?Copy link to section

The endpoint of our running example was fyf\,y. Categorically, application is described by evaluation. At the types already fixed in the example, write

evO:(OO)&OO,\operatorname{ev}_O: (O\Rightarrow O)\mathbin{\&}O \longrightarrow O,

with

evOf,y=fy.\operatorname{ev}_O\langle f,y\rangle=f\,y.

Currying evaluation turns the stored function into a lambda abstraction:

K(evO)(f)=λz:O.evOf,z=λz:O.fz.K(\operatorname{ev}_O)(f) = \lambda z:O.\,\operatorname{ev}_O\langle f,z\rangle = \lambda z:O.\,fz.

Uncurrying it again recreates an application, and therefore a beta redex:

LK(evO)f,y=K(evO)(f)(y)=(λz:O.fz)yβfy=evOf,y.\begin{aligned} LK(\operatorname{ev}_O)\langle f,y\rangle &= K(\operatorname{ev}_O)(f)(y)\\ &= (\lambda z:O.\,fz)y\\ &\Rightarrow_\beta f\,y = \operatorname{ev}_O\langle f,y\rangle. \end{aligned}

The original endpoint has now reappeared for a structural reason: currying introduces the abstraction λz.fz\lambda z.fz, and uncurrying exposes the beta step that removes it.

In an ordinary cartesian closed category, product with OO is left adjoint to function space out of OO. Here C(X,Y)\mathcal C(X,Y) means the set of arrows from XX to YY. Saying that the two constructions are adjoint means, at this ordinary one-dimensional level, that currying gives a natural bijection

C(A&O,B)C(A,OB).\mathcal C(A\mathbin{\&}O,B) \cong \mathcal C(A,O\Rightarrow B).

When beta and eta are equations, currying and uncurrying are inverse maps. In LAMBDA, the arrows from one type to another form a hom-category: terms are its objects, and conversions between parallel terms are its morphisms. Currying and uncurrying now give functors between these hom-categories.

Call currying KK and uncurrying LL:

K:LAMBDA(A&O,B)LAMBDA(A,OB),K: \mathbf{LAMBDA}(A\mathbin{\&}O,B) \longrightarrow \mathbf{LAMBDA}(A,O\Rightarrow B), L:LAMBDA(A,OB)LAMBDA(A&O,B).L: \mathbf{LAMBDA}(A,O\Rightarrow B) \longrightarrow \mathbf{LAMBDA}(A\mathbin{\&}O,B).

Let d:A&OBd:A\mathbin{\&}O\to B. Currying isolates the OO input:

K(d)(x)=λz:O.dx,z.K(d)(x) = \lambda z:O.\,d\langle x,z\rangle.

Let c:A(OB)c:A\to(O\Rightarrow B). Uncurrying applies the function stored at the first projection to the argument stored at the second:

L(c)(u)=c(fstu)(sndu).L(c)(u) = c(\operatorname{fst}u)(\operatorname{snd}u).

Now we can derive one composite line by line:

LK(d)(u)=K(d)(fstu)(sndu)by the definition of L,=(λz.dfstu,z)(sndu)by the definition of K,βdfstu,snduby one beta contraction,=d(u)by product eta, treated as equality.\begin{aligned} LK(d)(u) &= K(d)(\operatorname{fst}u)(\operatorname{snd}u) &&\text{by the definition of }L,\\ &= (\lambda z.\,d\langle \operatorname{fst}u,z\rangle) (\operatorname{snd}u) &&\text{by the definition of }K,\\ &\Rightarrow_\beta d\langle \operatorname{fst}u,\operatorname{snd}u\rangle &&\text{by one beta contraction},\\ &= d(u) &&\text{by product eta, treated as equality}. \end{aligned}

Thus beta supplies a conversion

LK(d)d.LK(d)\Rightarrow d.

For the other composite, unfold the definitions again:

KL(c)(x)=λz.L(c)x,z,=λz.c(fstx,z)(sndx,z)by the definition of L,=λz.c(x)(z)by the product beta equalities.\begin{aligned} KL(c)(x) &= \lambda z.\,L(c)\langle x,z\rangle,\\ &= \lambda z.\,c(\operatorname{fst}\langle x,z\rangle) (\operatorname{snd}\langle x,z\rangle) &&\text{by the definition of }L,\\ &= \lambda z.\,c(x)(z) &&\text{by the product beta equalities}. \end{aligned}

Seely's eta orientation points from c(x)c(x) to this expanded term:

c(x)ηλz.c(x)(z)=KL(c)(x).c(x) \Rightarrow_\eta \lambda z.\,c(x)(z) = KL(c)(x).

So eta supplies candidate cells 1KL1\Rightarrow KL, while beta supplies LK1LK\Rightarrow 1. The two calculations alone do not yet prove an adjunction. The cells must be natural in the terms they transform, and both triangle identities must hold. Seely's naturality and coherence equations establish those facts. With those equations in place, eta and beta are the unit and counit of

LK.L\dashv K.

This is the payoff. Currying and uncurrying are no longer inverse functions between hom-sets. They are adjoint functors between hom-categories, and the computations that used to disappear into equality now witness the adjunction.

One of the triangle calculations has a direct computational reading. At evaluation, eta followed by beta gives

fyη(λz.fz)yβfy.f\,y \Rightarrow_\eta (\lambda z.fz)y \Rightarrow_\beta f\,y.

Seely imposes that this matching eta-beta operation acts as the identity conversion, and the corresponding coherence equation handles the other triangle. The raw two-step history does not become an identity by endpoint equality alone.

6. Where does laxity enter?Copy link to section

The adjunction above varies with its types. To understand why that variation is not strict, reuse the type OO from the running example and consider the function-space constructor

G(A)=OA.G(A)=O\Rightarrow A.

Suppose m:BAm:B\to A. The induced map

G(m):(OB)(OA)G(m):(O\Rightarrow B)\to(O\Rightarrow A)

takes a function g:OBg:O\Rightarrow B and postcomposes it with mm:

G(m)(g)=λz:O.m(gz).G(m)(g)=\lambda z:O.\,m(gz).

Now let n:CBn:C\to B and start with g:OCg:O\Rightarrow C. Applying G(n)G(n) and then G(m)G(m) creates a beta redex that the direct composite does not contain:

G(m)(G(n)(g))=λz:O.m((λw:O.n(gw))z)unfold G twice,βλz:O.m(n(gz))contract the introduced redex,=G(mn)(g)recognize ordinary composition.\begin{aligned} G(m)(G(n)(g)) &= \lambda z:O.\, m\big((\lambda w:O.\,n(gw))z\big) &&\text{unfold }G\text{ twice},\\ &\Rightarrow_\beta \lambda z:O.\,m(n(gz)) &&\text{contract the introduced redex},\\ &= G(m\circ n)(g) &&\text{recognize ordinary composition}. \end{aligned}

Check the types at the middle line. The term gzgz has type CC, so n(gz)n(gz) has type BB, and m(n(gz))m(n(gz)) has type AA. Abstracting over z:Oz:O therefore gives a term of type OAO\Rightarrow A on both sides.

The beta conversion above is the comparison 2-cell

G(m)G(n)G(mn).G(m)G(n) \Rightarrow G(m\circ n).

The identity comparison is the same eta expansion seen in the currying calculation. For q:OAq:O\Rightarrow A:

qηλz.qz=G(1A)(q).q \Rightarrow_\eta \lambda z.qz = G(1_A)(q).

This is what lax means here. It does not mean approximate or defective. Composition and identity are preserved through specified directed 2-cells rather than literal equalities.

This calculation exhibits the two comparison cells; it is not the whole lax functor proof. The constructor must also act on conversions, and the comparison cells must satisfy naturality, associativity, and identity coherence. Seely checks those remaining laws in the construction of LAMBDA.

Under Seely's treatment of products, F=&OF=-\mathbin{\&}O is strict, while G=OG=O\Rightarrow- is lax. The families KA,BK_{A,B} and LA,BL_{A,B} are strict in their first type argument and lax in their second. Seely packages the comparison cells, unit, and counit into what he calls a lax semantic adjunction. This is his specific 1987 notion, so it should not be renamed a strict modern 2-adjunction.

7. Can the two paths be represented in code?Copy link to section

Haskell is useful for a small companion because algebraic data types mirror terms, individual cells, and paths. The program below builds the two reductions of TT. It checks only their boundaries. It is not a type checker, a beta validator, or an implementation of Seely's quotient.

module Main (main) where
 
data Term
  = Var String
  | Const String
  | Lam String Term
  | App Term Term
  deriving (Eq)
 
instance Show Term where
  show (Var x) = x
  show (Const c) = c
  show (Lam x body) = "(λ" ++ x ++ "." ++ show body ++ ")"
  show (App fun arg) = "(" ++ show fun ++ " " ++ show arg ++ ")"
 
data Rule
  = Beta
  | Inside String Rule
  deriving (Eq, Show)
 
data Step = Step
  { source :: Term
  , target :: Term
  , rule :: Rule
  }
  deriving (Eq, Show)
 
type Path = [Step]
 
startOf :: Path -> Maybe Term
startOf [] = Nothing
startOf (step : _) = Just (source step)
 
endOf :: Path -> Maybe Term
endOf [] = Nothing
endOf steps = Just (target (last steps))
 
valid :: Path -> Bool
valid [] = True
valid [_] = True
valid (first : second : rest) =
  target first == source second && valid (second : rest)
 
liftStep :: String -> (Term -> Term) -> Step -> Step
liftStep context wrap step =
  Step
    (wrap (source step))
    (wrap (target step))
    (Inside context (rule step))
 
sameBoundary :: Path -> Path -> Bool
sameBoundary first second =
  case (startOf first, endOf first, startOf second, endOf second) of
    (Just a, Just b, Just c, Just d) -> a == c && b == d
    _ -> False
 
main :: IO ()
main = do
  let f = Const "f"
      y = Var "y"
      value = App f y
      inner = App (Lam "v" (Var "v")) value
      whole = App (Lam "u" (Var "u")) inner
 
      innerBeta = Step inner value Beta
      outerFirstStep = Step whole inner Beta
      outerAfterInner = Step (App (Lam "u" (Var "u")) value) value Beta
 
      outerFirst =
        [ outerFirstStep
        , innerBeta
        ]
 
      innerFirst =
        [ liftStep "argument of the outer application"
            (App (Lam "u" (Var "u"))) innerBeta
        , outerAfterInner
        ]
 
  print (valid outerFirst, valid innerFirst)
  print (sameBoundary outerFirst innerFirst)

The program prints

(True,True)
True

valid checks that the steps in a path can be composed vertically by comparing adjacent boundaries. liftStep models the action of a term context on a conversion, which is the computational idea behind horizontal composition. sameBoundary confirms that the two paths are parallel.

Parallel paths are not automatically equal. It would be wrong to identify every pair of paths with the same endpoints. Seely's interchange equation justifies identifying this particular pair because it performs the same outer and substituted conversions in opposite orders.

8. What does the construction preserve, and where does it stop?Copy link to section

The 2-category preserves more computational information than an equational model, but less than an operational trace semantics.

It does not preserve every scheduling choiceCopy link to section

Interchange already identified the two reductions of TT. In the appendix, Seely also requires beta conversions at different logical occurrences to commute. He remarks that this is computationally questionable because an operational model may care about their order.

The construction retains conversion cells modulo specified equations. It does not by itself record cost, evaluation strategy, concurrency, or every intermediate schedule.

The direction of eta is structuralCopy link to section

The unit in the hom-category adjunction points as

cλx.c(x).c\Rightarrow\lambda x.c(x).

If eta is reversed,

λx.c(x)c,\lambda x.c(x)\Rightarrow c,

the same unit points the wrong way. Section 4 of the paper develops a different and less regular construction, called a lax syntactic adjunction, for that orientation. Changing a rewrite direction changes the categorical property available from it.

Optional background: where the directions come fromCopy link to section

Seely reaches directed beta and eta through models of the untyped lambda calculus. Such a model has a domain DD and maps

h:D[DD],k:[DD]D.h:D\to[D\to D], \qquad k:[D\to D]\to D.

The map hh reads an element as a function, and kk encodes a function as an element. Replacing inverse equations by

1Dkh,hk1[DD]1_D\leq kh, \qquad hk\leq 1_{[D\to D]}

makes hh left adjoint to kk in an ordered setting. One inequality gives eta expansion and the other beta contraction. A partial order is a thin category, so Seely's move from inequalities to general hom-categories replaces one possible comparison by a possibly non-thin category of conversions.

This background explains the chosen directions, but it is not needed to follow the worked term or the currying calculation.

Optional extension: polymorphismCopy link to section

For second-order polymorphism, types also contain t.A\forall t.A. Seely organizes the resulting terms and conversions into an indexed 2-category called POLYLAMBDA. If WW adds an unused type variable, the sketched lax adjunction is

Wt.().W\dashv\forall t.(-).

Universal quantification is the lax right adjoint. The paper presents this final section as a mathematical sketch rather than a full development.

9. What mental model should remain?Copy link to section

The transferable idea is not simply that lambda calculus forms a 2-category. It is a sequence of consequences.

Equality remembers that two terms coincide but forgets the conversion between them. Keeping conversions makes them 2-cells. Because a computation must remain valid when substituted into a larger term, those cells compose both vertically and horizontally. Interchange makes the two compositions compatible, at the price of identifying some raw reduction orders.

Once beta and eta are directed cells, currying and uncurrying cannot remain strict inverses. Eta becomes the unit, beta becomes the counit, and the function-space constructor preserves composition through beta comparison cells. That is why laxity appears.

When an equation in a semantic model hides a process, Seely's paper suggests a useful question: can the equation be lifted to a directed cell, and which coherence equations must then be imposed so that the process remains compositional?

Sources and further readingCopy link to section

Continue reading

Related notes