typelevel / cats

Lightweight, modular, and extensible library for functional programming.
https://typelevel.org/cats/
Other
5.25k stars 1.21k forks source link

Removing MonoidK and SemigroupK #1932

Open edmundnoble opened 7 years ago

edmundnoble commented 7 years ago

This depends on newtypes; without newtypes, we can't really do this.

As far as I can see, no evidence has been presented that MonoidK and SemigroupK are useful abstractions. So far, all they exist to do is disambiguate instances of monoid and semigroup, which is the job of newtypes, and they do a worse job because they don't compose with ordinary monoids and semigroups; there is no implicit product of a Monoid with a MonoidK.

Edit: They also don't disambiguate instances well. There's two valid MonoidK's for Option, for example.

LukaJCB commented 7 years ago

Link to discussion over newtypes: #1800

kailuowang commented 7 years ago

Blocked by #1800

LukaJCB commented 7 years ago

When we do remove these, maybe we could add a type class, that offers alternative Monoid instances, kinda like Parallel. Then Users would not have to wrap and unwrap manually and can continue using alternative behaviours in a concise way. 🤔 It might even let us keep the <+> syntax if we so choose. WDYT?

edmundnoble commented 7 years ago

I don't think that makes sense myself, and actually I think after consideration that Parallel doesn't really either. Especially given that we're considering ZipList to be a "parallel" List monad; what we need is a type class for canonical higher-kinded isomorphisms.

Newtyping is the best way to do this sort of thing because type class instances should be composable, and bundling instances together in super-instances prevents composition of those smaller instances.

rossabaker commented 7 years ago

maybe we could add a type class, that offers alternative Monoid instances, kinda like Parallel

So this typeclass would provide def monoid[A]: Monoid[F[A]]? A new typeclass for alternative instances with alternative syntax sounds like the existing MonoidK, with that method added.

In #1928, we have a practical example of deriving a MonoidK[Kleisli[F, A, ?]] from a MonoidK[F]. In this ticket, I imagine we'd be deriving a Monoid[Kleisli[F, A, B]] from a Monoid[F[B]]. I think we would either be in the position of making everyone use a newtype in place of a more common F for the subset of users who need a monoid, or we would force that subset of users who need one to transform from F to the newtype and back wherever they do. Am I understanding this right?

johnynek commented 7 years ago

There is something interesting when you can make a Monoid[A] for all A. This is not that uncommon. Scalding's TypedPipe[?] spark's RDD[?] and or course List[?], Vector[?] etc...

Now, generally, I agree, you do just want the monoid.

I don't know that I have ever wanted a MonoidK but not an Alternative

I'm generally very +1 on only adding abstractions that pay their own way. We should have clear functions we want to write with these things that apply to several cases.

That said, I'm also hesitant to remove things once added (which I guess I am saying I am generally conservative when it comes to changes).