- Coproduct

One of the well known duals is *coproduct*, which is the dual of product. Prefixing with “co-” is the convention to name duals.

Here’s the definition of products again:

Definition 2.15.In any categoryC, a product diagram for the objects A and B consists of an object P and arrows p_{1}and p_{2}

satisfying the following UMP:Given any diagram of the form

there exists a unique u: X => P, making the diagram

commute, that is, such that x_{1}= p_{1}u and x_{2}= p_{2}u.

Flip the arrows around, and we get a coproduct diagram:

Since coproducts are unique up to isomorphism, we can denote the coproduct as *A + B*, and *[f, g]* for the arrow *u: A + B => X*.

The “coprojections”

iand_{1}: A => A + Biare usually called_{2}: B => A + Binjections, even though they need not be “injective” in any sense.

Similar to the way products related to product type encoded as `scala.Product`

, coproducts relate to the notion of sum type, or disjoint union type.

First way to encode *A + B* might be using sealed trait and case classes.

```
sealed trait XList[A]
object XList {
case class XNil[A]() extends XList[A]
case class XCons[A](head: A, rest: XList[A]) extends XList[A]
}
XList.XCons(1, XList.XNil[Int])
// res0: XList.XCons[Int] = XCons(head = 1, rest = XNil())
```

If we squint `Either`

can be considered a union type. We can define a type alias called `|:`

for `Either`

as follows:

```
type |:[+A1, +A2] = Either[A1, A2]
```

Because Scala allows infix syntax for type constructors, we can write `Either[String, Int]`

as `String |: Int`

.

```
val x: String |: Int = Right(1)
// x: String |: Int = Right(value = 1)
```

Thus far I’ve only used normal Scala features only. Cats provides a typeclass called `cats.Inject`

that represents injections *i _{1}: A => A + B* and

```
import cats._, cats.data._, cats.syntax.all._
val a = Inject[String, String |: Int].inj("a")
// a: String |: Int = Left(value = "a")
val one = Inject[Int, String |: Int].inj(1)
// one: String |: Int = Right(value = 1)
```

To retrieve the value back you can call `prj`

:

```
Inject[String, String |: Int].prj(a)
// res1: Option[String] = Some(value = "a")
Inject[String, String |: Int].prj(one)
// res2: Option[String] = None
```

We can also make it look nice by using `apply`

and `unapply`

:

```
lazy val StringInj = Inject[String, String |: Int]
lazy val IntInj = Inject[Int, String |: Int]
val b = StringInj("b")
// b: String |: Int = Left(value = "b")
val two = IntInj(2)
// two: String |: Int = Right(value = 2)
two match {
case StringInj(x) => x
case IntInj(x) => x.show + "!"
}
// res3: String = "2!"
```

The reason I put colon in `|:`

is to make it right-associative. This matters when you expand to three types:

```
val three = Inject[Int, String |: Int |: Boolean].inj(3)
// three: String |: Int |: Boolean = Right(value = Left(value = 3))
```

The return type is `String |: (Int |: Boolean)`

.

An interesting read on this topic is Miles Sabin (@milessabin)’s Unboxed union types in Scala via the Curry-Howard isomorphism.

See also Coproducts and discriminated unions in Shapeless.

There’s a datatype in Cats called `EitherK[F[_], G[_], A]`

, which is an either on type constructor.

In Data types à la carte Wouter Swierstra (@wouterswierstra) describes how this could be used to solve the so-called Expression Problem.

That’s it for today.

herding cats — Coproduct