Arun Pandian M

Arun Pandian M

Android Dev | Full-Stack & AI Learner

From Types to Arrows: A Gentle Introduction

“Everything is connected.” — Cloud Atlas (2012)

When I first learned category theory, it felt like discovering a secret map underneath programming. It’s not about memorizing symbols — it’s about seeing connections, patterns, and journeys between things. Let’s explore this world using Kotlin and human-friendly analogies.

Objects (Types)

https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/fp_objects.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260117%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260117T134319Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=1b178c46c0be0988518a287c6679ed8b80ca73883d4c26c7e105791d9195840a6167eb6b849fe39954a599ec0e34889684f22b6a5985f971945ef42657911bbe330a7bfbf0dc302edfa080e56a3284a30d1cdd53d82e2913da3ff653971d4f92e10d9e6ec9ee0f5dbd0f84e80eb06ba860f5166ceaaf02c1e74a58a48af268192c2f322951599767e69ffd196f4228396ad681e2a3e87d0d5d7e7e5bd9749e1bfa311068080296b98ee39c1685310c5d974518c63ecdb2d9a358287c5aa9200b1f04634fac2ad52e0406e2fe278769fc2872e182b8f541f01fba0cb88d37ac64daf721b862b726ce958ae18f1c5e4733fedb3b8e8ee8ccd4faaa4377e039922c

Definition (Category Theory):

Objects are the fundamental entities in a category. They don’t do anything on their own; they just exist and provide structure.

In Kotlin:

Objects correspond to types — for example, Int, String, Boolean, List<T>, or even custom classes like data class User(val name: String, val age: Int).

val name: String = "Arun"
val age: Int = 28
val scores: List<Int> = listOf(10, 20, 30)

Expanded Explanation:

• Every object defines a domain for functions (arrows) to act upon.

Objects are containers of values — they describe what kind of data can exist.

• You can think of them as “stations” or “cities”: they hold information, but the magic happens when you connect them via arrows (functions).

Analogy for Beginners:

1. Cities on a Map:

• Each type is a city. Int city has numbers, String city has letters and words.

• You can visit these cities (create values), but to move information between cities, you need roads (functions).

2. Boxes:

• Each object is a box. You can store something inside it, but the box itself doesn’t do anything. Only when you pass it to a function (arrow) does action happen.

3. Real-Life Example:

• List<String> is like a basket of fruits. The basket itself is the type (object), but the fruits (values) inside can be transformed, sorted, or filtered using functions.

Objects themselves don’t change. They define the space of possibilities, while functions define what you can do within that space.

Morphisms (Functions as Arrows)

https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/morphisms.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260117%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260117T134319Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=09d2de79e28728ad281ea3f341d223cb59510ca0224c1e396b9fa43d49835a9682503f51203b734abf5a78592ceb8987d99d0397821dc365539765090063966eed5deaaec1e58546ad3e729f2d1af8cd639609e252a6cf20b7355e54c3c6ecbb58ca800ea2756393c5d855761cd25f5d63c35256e350c511c15ba8b5131871eb727dfbd77cc7f31612a37c1c0bd0f53278123c93ee443f6eb9e711afda55e43ed9e1bf2c14adee15be1188e4351e16e06032167e72f2824ab1c2bca4b73444530c52127decb2009f4b1326fd386beba408a1f2f83149810558a4d6f9c3053cefe593862b0caf80ab29ee5798d39ef1d5e34ef81e3fc2f50b1bbca1fc833c49d6

Definition (Category Theory):

A morphism is an arrow that connects two objects. It represents a relationship or transformation from one object to another. Every morphism has a source (starting object) and a target (ending object).

In Kotlin:

A morphism is any function that takes a value of one type and returns a value of another type (or the same type).

fun toUpper(s: String): String = s.uppercase() // String -> String
fun lengthOfString(s: String): Int = s.length   // String -> Int
fun isEven(n: Int): Boolean = n % 2 == 0       // Int -> Boolean

Expanded Explanation:

• Morphisms are actions that move or transform values between types.

• They are directional: you cannot use them backwards unless explicitly inverted

• They are pure descriptions of how one type relates to another — like a blueprint of a road connecting two cities

Analogy for Beginners:

1. Roads Between Cities:

• Types are cities. Functions are roads connecting these cities.

String -> Int is a road where a word is turned into a number (its length).

2. Conveyor Belt:

• Imagine a factory conveyor belt: you put an item (value of type A) at the start, it passes through a machine (function), and comes out transformed (value of type B).

3. Recipe Analogy:

• The function is a recipe: input ingredients (values) go in, the recipe (function) is applied, and the final dish (output) comes out.

• Example: lengthOfString("Kotlin") → 6

“The journey is just as important as the destination.” — Every function ever

Composition of Functions

https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/compose_block.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260117%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260117T134319Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=0392f0e5f0e7ff6893b7bf941ed36017c3351911153017ab8f33b070ba04587754f7d57ae34b4a55506e691f6112d229938f29052cebfb72f63fdf84a2c7f62acb898508f1938aabb42eb478f97b59177b2da7dba1092a33b91f1ce4d2428e620674378fafb8af6c33ddd852b7002819fd91fe15d8cf3bdaaf8bff9e76a7970a75cbf419bd6d42ad4f49ee509aea0ea4193d41d6e6d38cb4406592b56ddaf8da2e754bb8b2a979ddbfeaa90f993e8a5eb115c764fa4a79938aa19eb0958f0405210d715ea2d4982aae9e4714d0eb0a955212689dd584ab7f02432ea4709656d447d55fa491dcfa1c38b0697c8e6d82c1ccb752fce96403d898ec3e6debb0d1c7

Definition (Category Theory)

In Category Theory, composition is the rule that allows two morphisms to combine and form a new one.

Formally: If

f : A → B  
g : B → C

then their composition is

g ∘ f : A → C

That means — first apply f, then g.

Composition is associative, and every object has an identity morphism that doesn’t change the result when composed.

In Kotlin

fun trim(input: String): String = input.trim()
fun toUpper(input: String): String = input.uppercase()

// Manual composition
fun process(input: String): String = toUpper(trim(input))

println(process("  arun  ")) // Output: ARUN

Or functionally:

infix fun <A, B, C> ((A) -> B).andThen(g: (B) -> C): (A) -> C = { a -> g(this(a)) }

val process = ::trim andThen ::toUpper
println(process("  lambda  ")) // Output: LAMBDA

Expanded Explanation:

Composition is like chaining transformations.

Each function focuses on one task — trim cleans the input, toUpper transforms it.

By composing, you create a data flow:

input → clean → transform → result.

You don’t mutate the input; instead, you pipe data through pure functions.

This makes the code more modular, reusable, and testable — the essence of FP.

Analogy: Lego Blocks

Think of each function as a Lego block.

One shapes the piece, another colors it.

Alone, they do small jobs — but when snapped together, they build something new.

That’s function composition — small, reusable pieces combining to form powerful results.

“Big programs grow from small ones by composition.” — John Backus (Inventor of FP concepts)

Identity Morphism → The Mirror That Changes Nothing

https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/identity.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260117%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260117T134319Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=9aea2433879440a82fcf72294be6aa8cd6844bca78d50e61b13e9dbe1458343f82808f97d8f5b36944d0c94512550c4cc9beb5c2c8edc46fe1dd58aa742fa9c47ad2f153dfe18e3487113e9040c2c49855cc559266b71db2bc765867a8a97923b346bba5a7eeab30fb2b85f602511e07cc26904e8593656b13cb8b2c90edbef34a48382c04433421d4501086050f66c70cd22e53144a95179d471cba2e7209e5f79863e11b746b34fd01fe1ca4fe2f7f0f8055a4442f377ca5b36b09a105e0c80525b605eab8ed990802f7531d864777e32b5e9a20bc8c9a075c2b1bc2e0cfdc1831b72d9d30ce88694812911a5060173aa64f01278adcb4104eab4db8b6b8a6

Definition(Category Theory):

For every object A in a category, there exists a morphism

idA:AAid_A : A → A

such that for any morphism f : A → B:

fidA=f=idBff ∘ id_A = f = id_B ∘ f

In simpler words — an identity morphism is a function that, when composed with others, doesn’t change their behavior. It’s like pressing the “refresh” button but nothing actually changes — it just confirms the system still works.

In Kotlin example:

fun <T> identity(x: T): T = x

val value = 42
println(identity(value)) // Output: 42

// Composition with identity
val double: (Int) -> Int = { it * 2 }
val composed = double.compose(::identity)
println(composed(5)) // Output: 10

Here, the identity function doesn’t modify the data — it simply returns it. When used in composition, it behaves like a neutral element, much like 0 in addition or 1 in multiplication.

Analogy: The Perfect Mirror

The identity morphism is that mirror in the world of functions. Whatever you give it, it gives back unchanged.

“Sometimes doing nothing is the most powerful thing you can do — especially when it keeps the system consistent.”

Expanded Explanation:

The identity morphism ensures structural consistency within a category. It acts as the “glue” that guarantees composition behaves properly.

Every object (or type) in your system needs its own id to say:

“I can map myself to myself without losing meaning.”

This is foundational to Category Theory — without identity morphisms, you can’t define a valid category!

Wrapping Up

We’ve taken our first gentle steps into the world of Category Theory — not as mathematicians, but as curious developers trying to see the bigger picture behind functions, types, and composition.

We started with simple objects (types like Int, String), connected them with morphisms (functions as arrows), learned how these arrows compose, and finally met the humble identity morphism, the function that changes nothing yet means everything.

If all this still feels abstract — that’s perfectly fine. Category Theory is like learning to see code from a higher altitude — at first, things look blurry, but soon the patterns become beautiful and natural.

As the proverb goes:

“The beginning of wisdom is calling things by their right names.”

Now, you know the names — objects, morphisms, composition, and identity. In the next blog, we’ll go a bit deeper and explore how these ideas evolve into functors and mappings between categories — the real bridge between mathematics and programming.

Until then, keep composing functions, stay curious, and remember:

Every big abstraction starts with a small arrow.

#kotlin_fp#fp_basics#category_theory#functional_programming#pure_functions#kotlin_developers#morphisms#function_composition#arrows_in_fp#identity_function#functor_intuition#type_theory#developer_mathematics#fp_patterns