User:Michiexile/MATH198/Lecture 5

From HaskellWiki
Jump to: navigation, search


Cartesian Closed Categories and typed lambda-calculus

A category is said to have pairwise products if for any objects A,B, there is a product object A\times B.

A category is said to have pairwise coproducts if for any objects A,B, there is a coproduct object A+B.

Recall when we talked about internal homs in Lecture 2. We can now define what we mean, formally, by the concept:

Definition An object C in a category D is an internal hom object or an exponential object [A\to B] or B^A if it comes equipped with an arrow ev: [A\to B] \times A \to B, called the evaluation arrow, such that for any other arrow f: C\times A\to B, there is a unique arrow \lambda f: C\to [A\to B] such that the composite

C\times A\to^{\lambda f\times 1_A} [A\to B]\times A\to^{ev} B

is f.

The idea here is that with something in an exponential object, and something in the source of the arrows we imagine live inside the exponential, we can produce the evaluation of the arrow at the source to produce something in the target. Using global elements, this reasoning comes through in a more natural manner: given f: 1\to [A\to B] and x: 1\to A we can produce the global element f(x) = ev \circ f\times x: 1\to B. Furthermore, we can always produce something in the exponential whenever we have something that looks as if it should be there.

And with this we can define

Definition A category C is a Cartesian Closed Category or a CCC if:

  1. C has a terminal object 1
  2. Each pair of objects A, B\in C_0 has a product A\times B and projections p_1:A\times B\to A, p_2:A\times B\to B.
  3. For every pair A, B\in C_0 of objects, there is an exponential object [A\to B] with an evaluation map [A\to B]\times A\to B.


Note that the exponential as described here is exactly what we need in order to discuss the Haskell concept of multi-parameter functions. If we consider the type of a binary function in Haskell:

binFunction :: a -> a -> a

This function really lives in the Haskell type a -> (a -> a), and thus is an element in the repeated exponential object [A \to [A\to A]]. Evaluating once gives us a single-parameter function, the first parameter consumed by the first evaluation, and we can evaluate a second time, feeding in the second parameter to get an end result from the function.

On the other hand, we can feed in both values at once, and get

binFunction' :: (a,a) -> a

which lives in the exponential object [A\times A\to A].

These are genuinely different objects, but they seem to do the same thing: consume two distinct values to produce a third value. The resolution of the difference lies, again, in a recognition from Set theory: there is an isomorphism

Hom(S, Hom(T, V)) = Hom(S\times T, V)

which we can use as inspiration for an isomorphism Hom(S,[T\to V]) = Hom(S\times T, V) valid in Cartesian Closed Categories.

Typed lambda-calculus

The lambda-calculus, and later the typed lambda-calculus both act as foundational bases for computer science, and computer programming in particular. The idea in both is that everything is a function, and we can reduce the act of programming to function application; which in turn can be analyzed using expression rewriting rules that encapsulate the act of computation in a sequence of formal rewrites.

Definition A typed lambda-calculus is a formal theory with types, terms, variables and equations. Each term a has a type A associated to it, and we write a:A or a\in A. The system is subject to a sequence of rules:

  1. There is a type 1. Hence, the empty lambda calculus is excluded.
  2. If A, B are types, then so are A\times B and [A\to B]. These are, initially, just additional symbols, not imbued with the associations we usually give the symbols used.
  3. There is a term *:1. Hence, the lambda calculus without any terms is excluded.
  4. For each type A, there is an infinite (countable) supply of terms x_A^i:A.
  5. If a:A, b:B are terms, then there is a term (a,b):A\times B.
  6. If c:A\times B then there are terms proj_1(c):A, proj_2(c):B.
  7. If a:A And f:[A\to B], then there is a term f a:B.
  8. If x:A is a variable and \phi(x):B is a term, then there is a \lambda_{x\in A}\phi(x):[A\to B]. Note that here, \phi(x) is a meta-expression, meaning we have SOME lambda-calculus expression that may include the variable x.
  9. There is a relation a=_Xa' for each set of variables X that occur freely in either a or a'. This relation is reflexive, symmetric and transitive. Recall that a variable is free in a term if it is not in the scope of a \lambda-expression naming that variable.
  10. If a:1 then a=_{\{\}}*. In other words, up to lambda-calculus equality, there is only one value of type *.
  11. If X\subseteq Y, then a=_Xa' implies a=_Ya'. Binding more variables gives less freedom, not more, and thus cannot suddenly make equal expressions differ.
  12. a=_Xa' implies f a=_Xf a'.
  13. f=_Xf' implies f a=_Xf' a. So equality plays nice with function application.
  14. \phi(x) =_{X\cup \{x\}} \phi'(x) implies \lambda_x \phi(x) =_X \lambda_x \phi'(x). Equality behaves well with respect to binding variables.
  15. proj_1(a,b) =_X a, proj_2(a,b) =_Xb, c=_X(proj_1(c),proj_2(c)) for all a,b,c,X.
  16. \lambda_x\phi(x) a =_X \phi(a) if a is substitutable for x in \phi(x) and \phi(a) is what we get by substituting each occurrence of x bya in \phi(x). A term is substitutable for another if by performing the substitution, no occurrence of any variable in the term becomes bound,
  17. \lambda_{x\in A}f x =_X f, provided <math>x\not\in X.
  18. \lambda_{x\in A}\phi(x) =_X \lambda_{x'\in A}\phi(x') if x' is substitutable for x in \phi(x) and each variable is not free in the other expression.

Note that =_X is just a symbol. The axioms above give it properties that work a lot like equality, but two lambda calculus-equal terms are not equal unless they are identical. However, a=_Xb tells us that in any model of this lambda calculus - where terms, types, et.c. are replaced with actual things (mathematical objects, say, or a programming language semantics embedding typed lambda calculus) - then the things given by translating a and b into the model should end up being equal.

Any actual realization of typed lambda calculus is bound to have more rules and equalities than the ones listed here.

With these axioms in front of us, however, we can see how lambda calculus and Cartesian Closed Categories fit together: We can go back and forth between the wo concepts in a natural manner:

CCC to Lambda

Given a typed lambda calculus L, we can define a CCC C(L). Its objects are the types of L. An arrow from A to B is an equivalence class (under =_{\{x\}}) of terms of type B, free in a single variable x:A.

We need the equivalence classes because for any variable x:A, we want \lambda_xx: 1\to [A\to A] to be the global element of [A\to A] corresponding to the identity arrow. Hence, that variable must itself correspond to an identity arrow.

And then the rules for the various constructions enumerated in the axioms correspond closely to what we need to prove the resulting category to be cartesian closed.

Lambda to CCC

More on this subject can be found in:

  • Lambek & Scott: Aspects of higher order categorical logic and Introduction to higher order categorical logic

As it turns out, this is exactly what we need for \lambda-calculus. Any typed \lambda-calculus gives rise to a CCC in a natural manner, and any CCC has an internal language which satisfies, by the axioms for the CCC, all requirements to be a typed \lambda-calculus.

More importantly, by stating \lambda-calculus in terms of a CCC instead of in terms of terms and rewriting rules is that you can escape worrying about variable clashes, alpha reductions and composability - the categorical translation ignores, at least superficially, the variables, reduces terms with morphisms that have equality built in, and provides associative composition for free.

At this point, I'd recommend reading more on Wikipedia [1] and [2], as well as in Lambek & Scott: Introduction to Higher Order Categorical Logic. The book by Lambek & Scott goes into great depth on these issues, but may be less than friendly to a novice.

Limits and colimits

  • Generalizing these constructions
  • Diagram and universal object mapping to (from) the diagram
  • Express product/coproduct as limit/colimit
  • Issues with Haskell
    • No dependent types
    • No compiler-enforced equational conditions
    • Can be simulated but not enforced, e.g. using QuickCheck.

Useful limits and colimits

Equalizer, coequalizer
  • Kernels, cokernels, images, coimages
    • connect to linear algebra: null spaces et.c.
Pushout and pullback squares
  • Computer science applications


  1. Prove that currying/uncurrying are isomorphisms in a CCC. Hint: the map f\mapsto\lambda f is a map Hom(C\times A, B)\to Hom(C,[A\to B]).
  2. Prove that in a CCC, the composition \lambda \circ ev is \lambda\circ ev = 1_{[A\to B]}: [A\to B] \to [A\to B].
  3. * Implement a typed lambda calculus as an EDSL in Haskell.