-
Notifications
You must be signed in to change notification settings - Fork 4
Functors and Monads with Category Theory
A category consists of objects and arrows/morphisms between objects. There may be more than one arrow between objects, and arrows may point from an object to itself.
- You can compose arrows a:X->Y and b:Y->Z to make an arrow (b after a):X->Z, and arrow composition is associative.
- There is an identity arrow e:X->X that when composed with an arrow a:X->Y, (a after e) = a and when composed with an arrow b:Y->X, (e after b) = b.
Let's view all the object types in Java as the objects of a category. The pure functions can form arrows, based off the input type and output type of the functions. Functions can be composed, and the identity function can be defined for every type.
A functor is a mapping from the objects and arrows of a category to the objects and arrows of another category that preserves structure. That is, if arrow a:X->Y and b:Y->Z are arrows in category C, then F(a):F(X)->F(Y) and F(b):F(Y)->F(Z) are arrows in the category F(C). Since structure is preserved, F(b after a)=F(b) after F(a). Functors are also known as covariant functors. However, if structure is preserved in the reverse direction, such that F(b after a)=F(a) after F(b), this is a contravariant functor. These two terms also get used in generics, using a slightly different category.
We consider the Optional
functor mapping the object type T
to the object type Optional<T>
. Every object type can be mapped, using Optional.of
(or Optional.ofNullable
). A function f
can be changed into x->x.map(f)
so that it can work with an Optional<>
input.
In general, generics that support mapping are essentially functors. Consider mapping T
to Stream<T>
, and every element in T
can be mapped using a function.
Consider the category of all Java types, where arrows go from superclasses to subclasses. We take a class to be super
or extends
itself. Essentially, this category demonstrates the idea of substitution, where superclass compile time types can store subclass runtime types.
However, if we consider the type of a Consumer
, then subclass types can be replaced with superclass types, drawing the arrows in the opposite direction on. The idea of reversing the direction of the arrows is related to the notion of a contravariant functor. If the arrows remain the same direction, that makes it a covariant functor.
We observe how generic types are defined.
<generic-types> return-type function-name(generic-type identifier, ...) {
// function body
}
Some of the types may need to be related to each other, for example, I might need T extends Number
. We can view this as a simple category of two objects, T
and Number
, and a nontrivial arrow from Number
to T
. We need to find a correspondence where this category matches up with the category of all Java types, that is a functor.
Consider making an array T[]
. It can store any object which is T
or of a subclass of T
.
Object[] objArr = new Integer[30]; // okay
objArr[0] = ""; // oh no
Peer Learning
Guides
Setting Up Checkstyle
Setting Up Java
Setting Up MacVim
Setting Up Stu
Setting Up Unix For Mac
Setting Up Unix For Windows
Setting Up Vim
Setting up SSH Config
SSH Without Password
Copying Files From PE Nodes
Using tmux
CS2030 Contents
Lecture 1 SummaryLecture 2 Summary
Access Modifiers
Lecture 3 Summary (Polymorphism)
Compile Time Type VS Runtime Type
Abstraction, Encapsulation, Inheritance, and Polymorphism
SOLID Principles
Class VS Abstract Class VS Interface
Comparable VS Comparator
Generic Types T
HashMap
Raw Types with Generic
Lambda expression
PECS (Producer Extends Consumer Super)
Optional
Streams
Parallel Streams
Monad
Functors and Monads with Category Theory