5

In cats there are 2 semigroup types classes: Semigroup and SemigroupK with the latter working on type constructors. I fail to see the advantages of the latter over the former. If I look at the list instances they are providing Monoid (although there is a MonoidK), whereas NonEmptyList is providing a SemigroupK. Note that NonEmptyList is also providing a Semigroup via the following method:

implicit def catsDataSemigroupForNonEmptyList[A]: Semigroup[NonEmptyList[A]] =
  SemigroupK[NonEmptyList].algebra[A]

Why the discrepancy?

Then it seems that most semigroup operations are only available on Semigroup and not SemigroupK (there's reduceK in Reducible but that's the only one I saw, and it delegates to reduce which works on Semigroup).

So, given a type T[_], what would you gain by having both a SemigroupK[T] and a Semigroup[T[A]] for some A?

Edit

There's now an issue to remove MonoidK and SemigroupK: https://github.com/typelevel/cats/issues/1932

Bruno Bieth
  • 2,317
  • 20
  • 31
  • http://eed3si9n.com/herding-cats/SemigroupK.html You may want take a look at this – jilen Nov 07 '16 at 10:23
  • From what I can tell cats provides a `SemigroupK` for both `List` and `NonEmptyList` in `0.8`. If you take a look at `catsStdInstancesForList` the `MonadCombine` in there extends a `SemigroupK`. – Denis Rosca Nov 07 '16 at 10:31
  • @jilen I read this but it's not really answering my question – Bruno Bieth Nov 07 '16 at 12:07
  • @DenisRosca I saw that on cats 0.7.2, so it's possible that it got added in a later release, which still makes me wonder what you're gaining by having both type classes? – Bruno Bieth Nov 07 '16 at 12:09
  • For future reference: the Cats documentation for [`Semigroup`](http://typelevel.org/cats/typeclasses/semigroup.html) and [`SemigroupK`](http://typelevel.org/cats/typeclasses/semigroupk.html). – Peter Neyens Dec 01 '16 at 18:05

1 Answers1

0

One thing you can do with SemigroupK which you can't do with Semigroup is to compose instances for Nested:

implicit def catsDataSemigroupKForNested[F[_]: SemigroupK, G[_]]: SemigroupK[Nested[F, G, ?]]

If you try to write an equivalent for Semigroup, I think the closest you would get is

implicit def catsDataSemigroupForNested[F[_], G[_], A](implicit sg: Semigroup[F[G[A]]]): Semigroup[F[G[A]]] // or Semigroup[Nested[F, G, A]]

which is not very useful! From search, I can't see anything else which is implemented for SemigroupK and can't be done using Semigroup, but I might have missed something.

But the main point of SemigroupK is that once you have it, you can automatically get a Semigroup too, exactly like NonEmptyList does.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Ok, so I guess `Nested` and the `<+>` operator which has a slightly different semantic are so far the 2 reasons. But when you say that once you get a `SemigroupK` you can have a `Semigroup`, I would rather say that once you have that `SemigroupK` you _must_ get a `Semigroup`, otherwise it wouldn't be much useful (so I wouldn't call that a feature). – Bruno Bieth Nov 08 '16 at 09:04
  • No, you can use `SemigroupK` directly without getting a `Semigroup`: that's what `<+>` is for. (I personally would consider a mismatch between `<+>` and `|+|` like the one `Option` has to be a minor misfeature which is probably not worth getting rid of, not a reason to use `SemigroupK`; but I guess the instance for `Semigroup` was added before `SemigroupK` existed.) – Alexey Romanov Nov 08 '16 at 10:49