Haskell is a language deeply rooted in category theory. But as you don’t need to study the root system of Vitis vinifera in order to enjoy a glass of wine, you don’t need to know much about category theory in order to program in Haskell. Nevertheless, some of us just can’t help ourselves. We have to dig into the rich terroir of category theory to gain deeper insight into the art of functional programming. And today I’d like to talk about functions.
The basic category-theoretical model for Haskell is the category Hask, where objects are Haskell types, and morphisms are functions. The problem with this picture is that it puts functions on a different footing than the rest of the language. Functions from type A to type B — in other words, morphisms from object A to object B in Hask — form a set. This set is called the hom set, Hom(A, B). The fact that it’s just a set and not something bigger is a property of Hask — the property of being locally small. But in Haskell functions from type A to type B also form a type A->B. A type is an object in Hask. So what’s the connection between the set Hom(A, B) and the object A->B? The answer to this question is very interesting and involves products, exponentials, currying, and of course universal constructions.
In my previous blog I talked about the universal construction of limits — objects that represent relationships between other objects. In particular, a product can be defined as such a limit representing the most trivial relationship between two objects — that of just being two objects. Morphisms are also involved in relationships between objects, so maybe there is a way of representing them as an object as well. And indeed, it’s possible to define an object to represent a set of morphisms between two other objects A and B. Such an object is called the exponential and denoted by BA.
Notice that the domain A of the morphisms appears in the exponent. That might seem odd at first, but it makes perfect sense if you consider the relationship between multiplication (product) and exponentiation. In arithmetic, mn means m multiplied by itself n times. If you replace m and n with types (for simplicity, think of types as sets of values) and multiplication with (set-theoretical) product, you can think of mn as a set of n-tuples of values of type m: (m1, m2, m3,… mn). Of course, if n is a type, it’s not immediately clear what an n-tuple is (it’s a categorical power), but you can gain some intuition if you consider enumerated finite types. For instance, functions from Bool
to any type m
, Bool->m
, can be represented as all possible pairs of m
s (one value for True
and one for False
). They correspond to the exponential mBool
. Also, for finite types, the number of different functions from n to m is equal to mn. But the connection between products and exponentials goes deeper than that.
Universal Construction
The basic relationship describing a function is that of application. Given a pair (function, argument), produce a result. It terms of types, a function of type X->Y
applied to X
produces Y
. We want to define the exponential object YX to model this relationship. How do we do that?
There isn’t really that much choice. We need to map a pair of objects (YX, X) to Y. But what is a pair, and what does it mean to map? We can represent the pair as an object — a product of YX × X — and then we can map it to Y using a morphism, which we’ll call app
.
It immediately follows that we can’t define exponential objects if we don’t have products. Again, it kind of make intuitive sense — exponentiation arising from iterated multiplication.
From previous experience we know that having a relationship between objects is usually not enough to define a new object. There may be many other objects that model this relationship. We need a way to compare them and pick the one that models it best.
So suppose that we have an impostor object Z, together with a morphism g from Z × X to Y impersonating application. We know that our choice for YX is universal if for any Z and g there is a unique morphism, which we’ll call λg, that maps Z to YX, and which factors through app
:
g = app . (λg, id)
Such universal object might not exist in every category, but it does in Hask. In general, a category in which there is a terminal object, a product of any two objects, and an exponential of any two objects is called Cartesian closed. Cartesian closed categories are, for obvious reasons, very important in computer science.
Currying
There’s another way of looking at the diagram that defines the exponential object. You can think of the morphism g as a function of two variables:
g :: (Z, X) -> Y
For any such g there is a unique morphism λg that maps Z to YX, an object representing a function from X to Y. This establishes a one-to-one correspondence between functions of two variables and functions returning functions, which we know under the name of currying. So currying “falls out” of the definition of the exponential object.
Adjunction
Any time there is a one-to-one correspondence between sets of morphisms you might want to look for an underlying adjunction. You might remember from my previous blog post that a functor F is said to be left adjoint to the functor G (or G right adjoint to F) if the following two hom sets are naturally isomorphic:
Hom(FZ, Y) ~ Hom(Z, GY)
In our case we have a one-to-one mapping between the morphism g from Z×X to Y and the morphism λg from Z to YX. In a category where all products and all exponentials exist, we can define these two functors:
FXZ = Z × X GXY = YX
In Haskell, these functors would be implemented as:
newtype F x z = F (z, x) instance Functor (F x) where fmap f (F (z, x)) = F (f z, x) newtype G x y = G (x -> y) instance Functor (G x) where fmap f (G g) = G (f . g)
and the isomorphism of hom sets would be given by the function phi
and its inverse phi'
:
phi :: (F x z -> y) -> z -> G x y phi f z = G $ \x -> f (F (z, x)) phi' :: (z -> G x y) -> F x z -> y phi' g (F (z, x)) = let G f = g z in f x
Exponentiation can thus be defined as the right adjoint of taking a product.
September 29, 2014 at 2:54 am
[…] usual universal construction of an exponential object YX can be easily reproduced in a magmatic category. We just replace the […]
January 25, 2015 at 3:43 pm
Is this a typo? “for finite types, the number of different functions from m to n is equal to m^n”
January 25, 2015 at 4:10 pm
@Chad: You’re right. Fixed!
May 3, 2018 at 4:58 pm
Is there a chance you can explain exponential laws in simple words? Why does category theory turn an easy math concept into an insurmountable conundrum? See http://www.cs.ox.ac.uk/ralf.hinze/LN.pdf pag 24: “the self adjoint is controvariant”? “it takes coproduct to product”?
Also, can you show some visible example of an “exponential object” in practice: for example, what is a product of two graph and which is the picture of an exponent of two graphs?
April 13, 2019 at 8:51 pm
But when we look at the exponential of matrices in mathematics, we find that the product of exponentials is the exponential of the sum only if the two matrices commute
https://math.stackexchange.com/q/3186550
Which is the corresponding condition in category theory? From my previous comment I was convinced that that law of exponentials was always true in category theory: now I suspect it should not be…?
April 14, 2019 at 12:19 am
Unlike matrix multiplication, categorical product is symmetric (up to isomorphism). There are categories with tensor product that is not symmetric and in those there is a difference between left exponential and right exponential, and the exponential laws are not satisfied.
April 14, 2019 at 2:48 am
Thank you!!!
Indeed I was searching and reading something about it and I found a statement regarding the von Neumann algebra which is the “free exponential” and the adjoint of the tensor product.
I also suspect this corresponds to the exponential of the Kronecker sum of matrices which is the Kronecker product of the exponential. So in my understanding a sort of detour/workaround for those non commutative categories (like matrices in my example) where the universal (symmetric) exponential doesn’t exist (but I can have misunderstood something, of course)
May 21, 2021 at 10:21 am
“Also, can you show some visible example of an “exponential object” in practice: for example, what is a product of two graph and which is the picture of an exponent of two graphs?”
AGREE ==> graph exponent graph would be nice example !
May 21, 2021 at 12:20 pm
There is a video about it on YouTube. https://www.youtube.com/watch?v=EAK1avS3QMQ