Seguimos con Monoides y Semigrupos.
Un semigrupo es solo la parte combinada de un monoide, sin elemento vacio.
Si bien muchos semigrupos también son monoides, hay algunos tipos de datos para los que no podemos definir un elemento vacío. Por ejemplo, acabamos de ver que la concatenación de secuencias y la suma de enteros son monoides. Sin embargo, si nos restringimos a secuencias no vacías y enteros positivos, ya no podemos definir un elemento vacío sensible. Cats tiene un tipo de datos NonEmptyList que tiene una implementación de Semigroup pero no una implementación de Monoide.
Una definición más precisa (aunque todavía simplificada) de Cats' Monoid es:
trait Semigroup[A] {
def combine(x: A, y: A): A
}
trait Monoid[A] extends Semigroup[A] {
def empty: A
}
Veremos este tipo de herencia a menudo cuando discutamos las clases de tipos. Proporciona modularidad y nos permite reutilizar el comportamiento. Si definimos un Monoide para un tipo A, obtenemos un Semigrupo gratis. De manera similar, si un método requiere un parámetro de tipo Semigroup[B], podemos pasar un Monoid[B] en su lugar.