Arun Pandian M

Arun Pandian M

Android Dev | Full-Stack & AI Learner

Written by: Arun Pandian MPublished on: Mar 23, 2026

Products — When Two Independent Things Become One Structure

In programming, we combine values all the time.

But rarely do we ask a deeper question:

Is there a correct way to combine things?

Not just a convenient way. Not just a common pattern. But a way that is universally right.

Category theory answers this using something called a universal construction. Instead of defining a structure directly, it defines it by how it relates to everything else.

And when we ask:

“What is the best way to combine two things?”

This perspective leads us to a fundamental idea:

The Product.

A product is not just a pair of values. It is the *most universal* way of combining them.

To make this concrete, consider something simple:

Latitude and longitude. Individually, they are just numbers. But when combined correctly, they represent a precise location on Earth. And when combined incorrectly… everything breaks.

So what does it mean to combine them correctly?

That’s exactly what the idea of a Product captures.

The Mathematical Idea

In category theory, a product of A and B is:

An object (A, B) with two projections:
π₁ : (A, B) → A  
π₂ : (A, B) → B

These just mean:

  • take first value
  • take second value
  • The Pattern (What really matters)

    We don’t define product by structure.

    We define it by behavior:

          c
         / \
        p   q
       /     \
      A       B
    https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/product.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260808%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260808T140008Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=186ab2ad17a8929e87dcf8b3532ce1bce8352a8abe8a815a7ac94a38dcdad0b6a68ea8f9602dc7ebc1088d2c25b94945671631c502d9869fceae4d421e91e75192117f07baee6675efc9bf6f1dbd4e9879f5e513801336d9faf85afdf0cf70c6600e4e77a17b808fa24c85ab2053a4daced9d1516ea7b1ecd8a820cf5f802b082167b9277a300bfd3dc52b07c17effff06918878ef18e57cf5889b1b98f638d754bb5f61c1981ae2ebaf6984d6f9017ba804290f56f82016edf777eb699775052aeb130145d1dbe27a3a6ba2fef6945e6703b3a2bf709646caa8d989d75c6e02cc00e3e33977ef3b00dd3489ad2b2239448ad5ac10619e35da6cb439d7482b73

    Key Idea

    If you have:

    p : C → A  
    q : C → B

    Then there must exist a unique function:

    m : C → (A, B)

    Factorizer (The Heart of Product)

    This function is called the factorizer:

    m(x) = (p(x), q(x))

    Kotlin Implementation

    fun <C, A, B> factorizer(
        p: (C) -> A,
        q: (C) -> B
    ): (C) -> Pair<A, B> = { x ->
        Pair(p(x), q(x))
    }

    Real Example — Latitude & Longitude

    Domain

    data class Location(
        val latitude: Double,
        val longitude: Double
    )

    Projections

    val getLatitude: (Location) -> Double = { it.latitude }
    val getLongitude: (Location) -> Double = { it.longitude }

    Type matches, meaning is wrong(Compiles!)

    val wrong = { loc: Location ->
        Pair(getLatitude(loc), getLatitude(loc)) // bug
    }

    Output:

    (12.97, 12.97)

    Here Longitude lost, Type system didn’t help

    Correct (Factorizer)

    val correct = factorizer(getLatitude, getLongitude)
    
    println(correct(Location(12.97, 77.59)))
    // (12.97, 77.59)

    Why Factorizer Matters

    It enforces laws:

    fst(m(x)) = p(x)  
    snd(m(x)) = q(x)

    Any function that breaks this is not a product

    Without ProductWith Product
    Many ways to combineOnly ONE valid way
    Easy bugsGuaranteed correctness
    No structureMathematical guarantee

    Real Use Case — Parallel Data Fetch

    A screen needs to show user info along with their posts.

    Define Combine

    fun <C, A, B> combine(
        f: (C) -> A,
        g: (C) -> B
    ): (C) -> Pair<A, B> = { x ->
        Pair(f(x), g(x))
    }

    Use combine

    val fetchAll = combine(
        ::fetchUser,
        ::fetchPosts
    )
    
    val result = fetchAll(userId)

    We are combining two independent computations into one.

    Parallel Version

    fun <C, A, B> combineAsync(
        f: suspend (C) -> A,
        g: suspend (C) -> B
    ): suspend (C) -> Pair<A, B> = { x ->
        coroutineScope {
            val a = async { f(x) }
            val b = async { g(x) }
            Pair(a.await(), b.await())
        }
    }
    val fetchAll = combineAsync(
        ::fetchUser,
        ::fetchPosts
    )
    
    val result = fetchAll(userId)

    When values are independent but needed together, they form a Product.

    https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/product_factorization.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260808%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260808T140008Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=00e8490230f8fceace07cd781e47f63e43739236504ec21a183e21d67b684cb1d650e574e28ee041fcb64775499fbac35f08164330804c1b0c5e748ed8686f64c97f11dbb1c382e9a6e3c3f61f2e5aaa2518e9c6cf6c9cd1e76370173eee89e95f784010d832a16b56809e38aa58d0042029a23866f14eb247b6b843f8a3e60955cf1d915e65d274e5c1cb1ce0599600d2301306e95cdaa5593c67cd4dbfb689faf272213629b2605fd08260cebb545fae2cd7490b1064bae63b552226e6e35c4324134cc6ee7f36e727cfcdb9f864926a38bf3666d5285662edfa8b2bc4866b36ad09504d83852131b41ef7c4a3497c40cd6ba0377c4772af40d7e4f252213f

    Final Takeaway

    A product is not just a pair.

    It is:

    A structure where every valid combination must pass through one unique path

    One-line Conclusion

    Product is not about combining values — it’s about guaranteeing the only correct way to combine them
    #MathForDevelopers#FunctionalProgramming#BuildInPublic#CategoryTheory#FPFoundations#ProgrammingConcepts#EngineeringMindset#KotlinFP#SoftwareDesign#LearnInPublic#TypeTheory#ComputerScience#TheoreticalCS#ProductType#DataModeling
    LAMBDA BRICKS