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%2F20260705%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260705T044432Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=a2504a936150022ea2076879afca78f9523255bd0b4b75dbd2a197b7c9c73a6c265ef941d026599f95482c56082cc4d13046de626a8f3a0bd0e34270e2ee42e63dea863d64aab7291a7c5b7a08f40940d370348355767c749199cf886f5cb96e61d881048f1ac97488021e186b638fbcb883f780a95cae0e4f963267f943ffccad1f2338627ca24d9aa5376ae389c390502467ff6cbe22b38a01df54b3e8015e74b9d3dc8ed1b8e55960b05cadd9a103e8af04f9fede15a98fa3a2fbf47dc7dee6dc4d406f9854fcdebd0eaa8b52fa635c5d9c1230ccf642e9acd8cd85432295e079e6f8f888d1027811a9fad6f8923d5f1f3cbf3412d73c01d5388706d3445b

    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%2F20260705%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260705T044432Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=3b1eeb6a13e0e05be7e387b313db8617ff1e8d48d29bb18249bb5c30d2bf80d2dc23dea04438ae5a2bdef5cad670b95600280583e166da7446776cc8a87d30c6de6f49562a4a680a0298c7c57f3375cb066d1b931efa5d2837659bc7ec42f6291f8eb9e8d61ebd6d7b392e82235cc9171fe6f463621bcb6eb44b7444d7037aa7ddfcfef5834a262843fd8072b44369b82ef7be991b7c1d46fb9729000dcf0c69f9504751d2f390e6a7e41c372c6c5f331fa88265abf4cd211c5afe1cbee09b24a781e958261b7e65add6a3392802a18dea1a57cb16f44bc06498eaf63a73b88bb1817a39d29fc01a3ba5abbd222fccf2258f5d642a206be31e3264a5c8dc09e8

    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