Category Theory Express Design Patterns

There are multiple design patterns present in sstreams. I am using the term "design patterns" broadly. Design patterns in a functional language can originate from category theory. For example the word "Monad" originates in category theory. We can use it to mean a design pattern. Some design patterns may translate directly into programming interfaces, others may not. We want to gloss most of the theory and focus on practical uses.

Design patterns provide abstractions for computations. Category theory does the same thing. Design patterns were made popular by the Gang of Four (GoF) and Martin Fowler and still represent a way to think about creating components in applications. For example, using the Singleton design pattern in an application signals that there will be only one instance of a type for the application. where a single instance of an object is used in your application. The Singleton object may represent a factory or service interface to other subsystems. A design pattern is independent of the syntax or programming model of all programming language. In reality, some design patterns are used more frequently in some languages than others. For example, the Dependency Injection design pattern is important in java but often less so, perhaps, than in scala. There are many examples where the programming language makes a specific design pattern more or less important or represents the design pattern directly in language constructs.

Category theory uses mathmatical concepts to express design patterns. For example, the pattern where you add two objects together is called Applicative in category theory. Adding two numbers together seems like a very fine grained concept to call out as a pattern. If you abstract adding two numbers together to adding two error messages together, adding an element to a list or adding two domain objects together, Applicative as a design pattern makes more sense. Category theory provides both fine grain design patterns and design patterns that can applied at a coarse grain. Between category theory and traditional design patterns, there is an abstraction for all elements of a program.

For example, if you need to add two numbers together, you would write

val x = 1 + 1

which is not very exciting. However, you could also write this as:

val myAdder(i1: Int, i2: Int, op: Op): Int = op.doit(i1, i2)

case class Op { def doit(i1: Int, i2: Int) = i1+i2 }

which demonstrates that you can take a builtin operator like plus (+) and turn it into an instance of a class that when an instance of that class is used, performs an operation. The method inside would merely add the two operands together. You can do this for all operators like +, - and *. When you expose these type of abstractions in your program, you write classes that expose an operation like + but abstracted and made into instances using classes like Op. By creating an instance of that class, you can pass around the operation as an object. In concept, your function becomes a parameter.

You can already pass around functions in scala as first class objects so you could skip the class declaration. For example, it may seem like alot of overhead for integer addition and that's true in the small example above. However, if your domain objects are not integers you will need to still write a function that takes the two domain objects as parameters and encodes the concept of addition into a mothed. It turns out that it is convenient for other reasons to encode the operation in a class. You run into this type of situation in java where the Strategy pattern is often used to "abstract" or "pull out" specific parts of a method call so you can replace the logic. For example, if you need to add a validation message to a list of validation messages during domain object validation, you need to include a concept of "adding two validation messages together." You would typically create an object that has an add method that would + a new message to the set of existing messages. Conceptually, it was still just addition.

When you use category theory thinking to expose basic operations, you are category theory as a design patterns in your application. Category theory has always been part of your programming bag of tricks. It much rarer that you abstract your application components in a way that uses category theory so succinctly using the same vocabulary. Scalaz exposes these design patterns directly.

In the short descriptions of the design patterns from category theory that are important to know, you can substitute a list object as an example most of the time when you try to visualize the design pattern. A list is a very general data structure that fits into many types of design patterns in category theory. It is also easy to visualize.

Last updated