-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide instance of Alternative[Set]
in alleycats
#3837
Provide instance of Alternative[Set]
in alleycats
#3837
Conversation
73962e2
to
1d5d3ec
Compare
override def empty[A]: Set[A] = Set.empty | ||
|
||
override def combineK[A](x: Set[A], y: Set[A]): Set[A] = x | y |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are duplicated from catsStdInstancesForSet
in cats-core
:
cats/core/src/main/scala/cats/instances/set.scala
Lines 23 to 25 in 3d900de
def empty[A]: Set[A] = Set.empty[A] | |
def combineK[A](x: Set[A], y: Set[A]): Set[A] = x | y |
...I wasn't sure if delegating to the cats-core
typeclass instance was the thing to do, or if it was clearer just to duplicate!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm okay with this. The duplication is slight and the laws ought to catch problems.
Alternative
for Set
in alleycats
Alternative
for Set
in alleycatsAlternative[Set]
in alleycats
This allows the use of methods from `Alternative` on a `Set` - for instance, I want to be able to use `separate` on a `Set`: ``` import cats.implicits._ import alleycats.std.set._ val stringsAndInts: Set[Either[String, Int]] = Set(Right(6),Left("Foo")) val (strings: Set[String], ints: Set[Int]) = stringsAndInts.separate ``` The `Alternative` typeclass just requires `MonoidK` (already provided for `Set` in `cats-core`) & `Applicative` (already provided for `Set` by `Monad` in `alleycats`, so adding it to `alleycats` is a small change. https://github.com/typelevel/cats/tree/main/alleycats-core#set_-instances
1d5d3ec
to
a900607
Compare
I think this PR is finally ready for review, but I'm not sure who to ask for review! - maybe @larsrh or @kailuowang ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this!
What happens if we try to summon a MonoidK[Set]
with this in scope? There's only one Alternative[Set]
, so your test passes, but there are now two MonoidK[Set]
instances, and I don't see a prioritization. I am not too familiar with alleycats, so perhaps there is precedent for a workaround. Or maybe it works, but I'd throw in a test for that to be sure. Also maybe try it from a REPL with the standard imports, just to be super sure.
override def empty[A]: Set[A] = Set.empty | ||
|
||
override def combineK[A](x: Set[A], y: Set[A]): Set[A] = x | y |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm okay with this. The duplication is slight and the laws ought to catch problems.
Thanks - that all makes sense, I will take a look at this a bit later 👍 |
I tried summoning a scala> import cats._
| import cats.data._
| import cats.implicits._
| import alleycats.std.all._
import cats._
import cats.data._
import cats.implicits._
import alleycats.std.all._
scala> implicitly[MonoidK[Set]]
^
error: ambiguous implicit values:
both value catsStdInstancesForSet in trait SetInstances of type cats.UnorderedTraverse[Set] with cats.MonoidK[Set]
and value alleyCatsStdSetMonad in trait SetInstances of type cats.Monad[Set] with cats.Alternative[Set]
match expected type cats.MonoidK[Set] I don't know how to get round this - if both imports ( |
I don't think we can get around that. Possibly the instance could be made non-implicit? |
Clients could get around it by excluding the cats one in the import, or using a la carte imports. But, yuck. Is this the first time we've needed to duplicate a cats instance as part of the hierarchy in an alleycats instance? I'm surprised this hasn't come up before. |
Alleycats' |
I think the problem here is that neither implicit is more specific, whereas |
But if someone asked for a |
The more specific implicit beats the less specific one every time:
|
I must have weekend brain, because I don't see why that should be different. What is "more specific"? |
You might be right ... maybe the actual problem here is that the |
Is it your REPL that's allowing the |
Yes, that is correct - neither is subtype of the other: |
@ import $ivy.`org.typelevel::alleycats-core:2.5.0`
import $ivy.$
@ import cats._, cats.data._, alleycats.std.all._
import cats._, cats.data._, alleycats.std.all._
@ implicitly[Traverse[({ type l[a] = Map[String, a] })#l]]
res2: Traverse[Map[String, a]] = alleycats.std.MapInstances$$anon$1@5f395ce1
@ implicitly[UnorderedTraverse[({ type l[a] = Map[String, a] })#l]]
res3: UnorderedTraverse[Map[String, a]] = alleycats.std.MapInstances$$anon$1@16f7f59f
@ import cats._, cats.data._, cats.implicits._, alleycats.std.all._
import cats._, cats.data._, cats.implicits._, alleycats.std.all._
@ implicitly[Traverse[({ type l[a] = Map[String, a] })#l]]
res5: Traverse[Map[String, a]] = alleycats.std.MapInstances$$anon$1@486dd616
@ implicitly[UnorderedTraverse[({ type l[a] = Map[String, a] })#l]]
cmd6.sc:1: ambiguous implicit values:
both method alleycatsStdInstancesForMap in trait MapInstances of type [K]cats.Traverse[[β$0$]scala.collection.immutable.Map[K,β$0$]]
and method catsStdInstancesForMap in trait MapInstances of type [K]cats.UnorderedTraverse[[β$0$]scala.collection.immutable.Map[K,β$0$]] with cats.FlatMap[[β$1$]scala.collection.immutable.Map[K,β$1$]] with cats.Align[[β$2$]scala.collection.immutable.Map[K,β$2$]]
match expected type cats.UnorderedTraverse[[a]scala.collection.immutable.Map[String,a]]
val res6 = implicitly[UnorderedTraverse[({ type l[a] = Map[String, a] })#l]]
^
Compilation Failed I bet this works without that import, too. |
@rossabaker is correct, so this PR is good to go. |
This allows the use of methods from
Alternative
on aSet
- for instance, I want to be able to useseparate
on aSet
:The
Alternative
typeclass just requiresMonoidK
(already provided forSet
incats-core
) &Applicative
(already provided forSet
byMonad
inalleycats
), so adding it toalleycats
is a small change.Here's a diagram I drew mainly for myself (!), as a novice contributing to Cats, to understand the typeclass relationships involved:
I did try running this - but it crashed on unrelated files like this: