### SemigroupK

Semigroup we saw on day 4 is a bread and butter of functional programming that shows up in many places.

``````scala> import cats._, cats.data._, cats.implicits._
import cats._
import cats.data._
import cats.implicits._
scala> List(1, 2, 3) |+| List(4, 5, 6)
res0: List[Int] = List(1, 2, 3, 4, 5, 6)
scala> "one" |+| "two"
res1: String = onetwo``````

There’s a similar typeclass called `SemigroupK` for type constructors `F[_]`.

``````@typeclass trait SemigroupK[F[_]] { self =>

/**
* Combine two F[A] values.
*/
@simulacrum.op("<+>", alias = true)
def combineK[A](x: F[A], y: F[A]): F[A]

/**
* Given a type A, create a concrete Semigroup[F[A]].
*/
def algebra[A]: Semigroup[F[A]] =
new Semigroup[F[A]] {
def combine(x: F[A], y: F[A]): F[A] = self.combineK(x, y)
}
}
``````

This enables `combineK` operator and its symbolic alias `<+>`. Let’s try using this.

``````scala> List(1, 2, 3) <+> List(4, 5, 6)
res2: List[Int] = List(1, 2, 3, 4, 5, 6)``````

Unlike `Semigroup`, `SemigroupK` works with any type parameter of `F[_]`.

#### Option as SemigroupK

`Option[A]` can form a `Semigroup` only when the type parameter `A` forms a `Semigroup`.

``````scala> case class Foo(x: String)
defined class Foo``````

So this won’t work:

``````scala> Foo("x").some |+| Foo("y").some
<console>:33: error: value |+| is not a member of Option[Foo]
Foo("x").some |+| Foo("y").some
^
``````

But this works fine:

``````scala> Foo("x").some <+> Foo("y").some
res3: Option[Foo] = Some(Foo(x))``````

There’s also a subtle difference in the behaviors of two typeclasses.

``````scala> 1.some |+| 2.some
res4: Option[Int] = Some(3)
scala> 1.some <+> 2.some
res5: Option[Int] = Some(1)``````

The `Semigroup` will combine the inner value of the `Option` whereas `SemigroupK` will just pick the first one.

#### SemigroupK laws

``````trait SemigroupKLaws[F[_]] {
implicit def F: SemigroupK[F]

def semigroupKAssociative[A](a: F[A], b: F[A], c: F[A]): IsEq[F[A]] =
F.combineK(F.combineK(a, b), c) <-> F.combineK(a, F.combineK(b, c))
}
``````