-
-
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
Created Copair typeclass #976
Conversation
Ideas for some laws: left(a).fold(f, g) == f(g)
right(b).fold(f, g) == g(b)
// left is associative
left(left(x, y), z) ~= left(x, left(y, z))
// similarly for right It can also extend/implement I have had a use case for this once I think, but I don't see this around much so I'm wondering if there's a reason for that.. Assuming there's no reason, there is possibly an analogous one abstracting over products. In general this design looks a lot like MTL/finally tagless (e.g. /cc @tpolecat since I saw him briefly discussing this with you on Gitter |
I had initially created this with an implicit function that would derive a |
Current coverage is 82.37%
@@ master #976 diff @@
==========================================
Files 215 219 +4
Lines 2704 2745 +41
Methods 2639 2681 +42
Messages 0 0
Branches 60 60
==========================================
+ Hits 2217 2261 +44
+ Misses 487 484 -3
Partials 0 0
|
@adelbertc I'm not sure what you mean by left(left(x, y), z) ~= left(x, left(y, z))
|
Ah yes my mistake, ignore that one |
I wonder if you can also define an instance for This LGTM, I've had a use case for this before I think, though I have (purely aesthetic) reservations about the name Copair. |
I'm not married to the name Another question, how to I get code coverage on the |
I just made up |
@adelbertc Looks like Haskell has a Upon further inspection, maybe Haskell's |
…e tests are written how they are.
…e tests are written how they are, increased test coverage
…ap" laws to catch a few cases where somebody could implement swap incorrectly.
@adelbertc after my (Short) investigation, it looks like you cannot define an instance for Whenever I tried to define fold ( I've added a I'm confident with |
Also something I just noticed, |
Conflicts: core/src/main/scala/cats/data/Validated.scala core/src/main/scala/cats/data/Xor.scala tests/src/test/scala/cats/tests/EitherTests.scala tests/src/test/scala/cats/tests/ValidatedTests.scala tests/src/test/scala/cats/tests/XorTests.scala
Updated branch and resolved conflicts |
I don't quite understand the codecov/changes error. Can I have some guidance on how to fix that? |
Thanks for putting this together @Jacoby6000. I'm not sure what to think about this. Since |
It may be that this construct doesnt belong in cats, but maybe something that extends cats in some way. Sometimes when developing libs, it's useful to accept/manipulate whatever Either construct somebody wants to use. Perhaps I can look at throwing this in some utility library. Perhaps it'd be a nice addition to Daniel's "Shims" |
It looks to me like this type-class captures the notion of the sum of two types As @ceedubs said, So your Usually, the notion of abstracting over algebraic properties of ADTs (algebraic data types) is called 'generic' programming, and that is what the shapeless library is concerned with (https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/ops/coproduct.scala for your specific use-case) |
@kcsongor I opened a PR in the kittens repo. I feel like |
Hm, what I meant was that kittens already has this abstraction, as this describes a binary sum of types. Of course, if you know how to represent the sum of two types, then you know how to represent the sum of n types, neither is more general. This is irrelevant, but: the link you posted earlier for Haskell is not quite the same thing. The docs say that Copair is dual to Unpair, where if Unpair eliminates a pair in a context, then Copair introduces one. The example states that this is useful for contravariant functors. That's because flipping the arrows of the product projections via some contravariant functor f, from |
@kcsongor I'm aware of what coproducts are and do. In short, my vision of this The fact that this is a generalization of all coproducts with arity 2 might be seen more clearly here: type ShapelessCoproduct2[A, B] = A :+: B :+: CNil
implicit val shapelessCoproductCopair: Copair[ShapelessCoproduct2] =
new Copair[ShapelessCoproduct2] {
def fold[A, B, C](f: CopairInstances.this.ShapelessCoproduct2[A,B])(fa: A => C,fb: B => C): C =
f match {
case Inl(a) => fa(a)
case Inr(Inl(b)) => fb(b)
case Inr(Inr(_)) => sys.error("impossible")
}
def left[A, B](a: A): CopairInstances.this.ShapelessCoproduct2[A,B] = Coproduct[ShapelessCoproduct2[A,B]](a)
def right[A, B](b: B): CopairInstances.this.ShapelessCoproduct2[A,B] = Coproduct[ShapelessCoproduct2[A,B]](b)
} |
"The typeclass I've created allows you to accept either one of those, provided you don't want behaviors specific to those two specific coproducts for example." - this is what data-type generics programming is for. Shapeless is able to derive this binary coproduct for both Either and Xor, I suggest you to look up how the library works, quite interesting! |
I'm very familiar with shapeless, and I'm not at all arguing that my |
I'm confused about what the added value here is. Would this be for people who essentially need the coproduct from shapeless, but prefer to write the instance by hand and/or don't want to add it to their classpath? |
Could you elaborate on the arity argument? For the record, coproducts are binary in shapeless. |
@kcsongor here's an example use of a It allows the caller of Shapeless When you say shapeless |
@Jacoby6000
As for your JSON example, I can only repeat what I've already said, that this is what data-type generic programming is, and it is precisely what shapeless is for. For this specific example, shapeless's coproduct.
|
I understand and agree with you on all fronts. I don't understand what conclusion you are making though. There is not yet a typeclass which represents the idea of Xor, Either, Validated, Coproduct... |
My point is that if you're the author of the library, you could write your functions with shapeless, and then the user wouldn't have to instantiate any type-class, just use their Xor or Validated, as they like, the transitions would be handled generically. That being said, there is indeed no facility in cats that generalises it. |
This is a PR attempting to take care of #974. I'm mostly looking for feedback right now, as I'm new to FP, and contributing to Cats.
A
Copair
is a generalization ofXor
,Either
, andValidated
.What's missing currently are tests, mainly because I'm not sure what lawsHowever I know there are more. These things just aren't intuitive to me yet.Copair
should have. I've thought off.swap.swap <-> f
but that's about it.I'm also looking for feedback on how to organize things.
As it stands now, there will be problems with ambiguous implicits, because of theI can move it somewhere to make this better, but I'm not sure where it should go. I'm also not sure where/how I should handle theBitraverse
derivation.CopairIdOps
class.