4.1 The Writer Category
In functional programming, we want every function to be Pure Functions. But how do we even start to do that for writing logs, which usually involves a mutable global state (the log)?
We can use the writer category for that.
Suppose we have two functions.
f1(int n) {return n+3;}
and
f2(int n) {return n*2;}
…and we want both of these functions to write a log to somewhere yet keeping each of the functions pure. What we can do is to actually make each of the function return a pair, like so:
f1(int n) {return make_pair(n+3,"added 3");}
f2(int n) {return make_pair(n*2,"multiplied by 2");}
And then, during the execution, compose the function as follows:
- Execute
f1
as usual. - Extract first element of the result (n+3) and give it to
f2
- Concatenate both the second elements of
f1
andf2
together. - Pair both of first element of the
f2
result and pair it with the concatenated string.
And there you have it! A pure function that also logs its activities.
Wait, what are writer categories again? It’s basically what we have done, kinda.
A writer category (very informal definition warning) here are just your usual categories where for each morphisms, beside the usual outputs, appends an additional information. Composition between objects in this category combines the additional information through monoid operation (i.e. concatenating strings) in a predetermined monoid .
4.2 Kleisli Categories
A writer category is a kind of Kleisli Category. Basically, a Kleisli Category has, as objects, the types of the underlying programming language. Morphisms from type A to type B are functions that go from A to a type derived from B using the particular embellishment.
Sounds confusing, huh? What I got from this is basically that Kleisli Category have morphism that’s like usual function, just that the return type is some sort of a derived type, like Writer. I’m pretty sure it has a stricter definition, but thinking of it this way helps a lot.