# SemigroupK

`SemigroupK`

has a very similar structure to `Semigroup`

, the difference
is that `SemigroupK`

operates on type constructors of one argument. So, for
example, whereas you can find a `Semigroup`

for types which are fully
specified like `Int`

or `List[Int]`

or `Option[Int]`

, you will find
`SemigroupK`

for type constructors like `List`

and `Option`

. These types
are type constructors in that you can think of them as "functions" in
the type space. You can think of the `List`

type as a function which
takes a concrete type, like `Int`

, and returns a concrete type:
`List[Int]`

. This pattern would also be referred to having ```
kind: * ->
*
```

, whereas `Int`

would have kind `*`

and `Map`

would have kind `*,* -> *`

,
and, in fact, the `K`

in `SemigroupK`

stands for `Kind`

.

First some imports.

```
import cats._
import cats.implicits._
```

For `List`

, the `Semigroup`

instance's `combine`

operation and the `SemigroupK`

instance's `combineK`

operation are both list concatenation:

```
SemigroupK[List].combineK(List(1,2,3), List(4,5,6)) == Semigroup[List[Int]].combine(List(1,2,3), List(4,5,6))
// res0: Boolean = true
```

However for `Option`

, the `Semigroup`

's `combine`

and the `SemigroupK`

's
`combineK`

operation differ. Since `Semigroup`

operates on fully specified
types, a `Semigroup[Option[A]]`

knows the concrete type of `A`

and will use
`Semigroup[A].combine`

to combine the inner `A`

s. Consequently,
`Semigroup[Option[A]].combine`

requires an implicit `Semigroup[A]`

.

In contrast, `SemigroupK[Option]`

operates on `Option`

where
the inner type is not fully specified and can be anything (i.e. is
"universally quantified"). Thus, we cannot know how to `combine`

two of them. Therefore, in the case of `Option`

the
`SemigroupK[Option].combineK`

method has no choice but to use the
`orElse`

method of Option:

```
Semigroup[Option[Int]].combine(Some(1), Some(2))
// res1: Option[Int] = Some(value = 3)
SemigroupK[Option].combineK(Some(1), Some(2))
// res2: Option[Int] = Some(value = 1)
SemigroupK[Option].combineK(Some(1), None)
// res3: Option[Int] = Some(value = 1)
SemigroupK[Option].combineK(None, Some(2))
// res4: Option[Int] = Some(value = 2)
```

There is inline syntax available for both `Semigroup`

and
`SemigroupK`

. Here we are following the convention from scalaz, that
`|+|`

is the operator from semigroup and that `<+>`

is the operator
from `SemigroupK`

(called `Plus`

in scalaz).

```
import cats.implicits._
val one = Option(1)
val two = Option(2)
val n: Option[Int] = None
```

Thus.

```
one |+| two
// res5: Option[Int] = Some(value = 3)
one <+> two
// res6: Option[Int] = Some(value = 1)
n |+| two
// res7: Option[Int] = Some(value = 2)
n <+> two
// res8: Option[Int] = Some(value = 2)
n |+| n
// res9: Option[Int] = None
n <+> n
// res10: Option[Int] = None
two |+| n
// res11: Option[Int] = Some(value = 2)
two <+> n
// res12: Option[Int] = Some(value = 2)
```

You'll notice that instead of declaring `one`

as `Some(1)`

, we chose
`Option(1)`

, and we added an explicit type declaration for `n`

. This is
because the `SemigroupK`

type class instances is defined for `Option`

,
not `Some`

or `None`

. If we try to use `Some`

or `None`

, we'll get errors:

```
Some(1) <+> None
None <+> Some(1)
// error: value <+> is not a member of Some[Int]
// Some(1) <+> None
// ^^^^^^^^^^^
```