-
Notifications
You must be signed in to change notification settings - Fork 114
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
Add forany and foranyPar to Traversable #392 #424
base: series/1.x
Are you sure you want to change the base?
Conversation
@@ -122,6 +122,24 @@ trait Traversable[F[+_]] extends Covariant[F] { | |||
} | |||
} | |||
|
|||
def forany[G[+ _] : AssociativeEither : IdentityBoth : Covariant, A, B](fa: F[A])(f: A => G[B]): G[Option[B]] = |
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.
IdentityEither is useless for these case, we don't want to use IdentityEither.none in case of empty traversable^ because it 'none' behaves like failure
So i requested IdentityBoth for any ; may be there should be separate typeclass in hierarchy that produces G[Any]?
I think we should give more attention for testing instances for effect types like ZIO, Future ... FutureCommutativeEither for example seems broken
If any future fails faster than another one completes, whole result is failed, but by CommutativeEither laws it should select sucessful result; ZIOCommutativeEither seems ok |
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.
Awesome work, thank you @Badmoonz
Wow, thanks for finding this. Any help with fixing the instance would be much appreciated 🙇 |
Also, as a stretch goal, do you think, you could implement analogous methods ( |
I see there's a conflict. Could you please resolve it @Badmoonz ? 🙏 |
ok |
You will also need to run |
7d1cae7
to
607561f
Compare
probably done :) |
Do you think you could also try the NonEmptyTraversable variants? 🙏 |
607561f
to
dc64475
Compare
sure :) within this issue( #392 )? |
dc64475
to
a161092
Compare
/** | ||
* The `IdentityBoth` instance for `ZIO`. | ||
*/ | ||
implicit def ZIOIdentityBoth[R, E]: IdentityBoth[({ type lambda[+a] = ZIO[R, E, a] })#lambda] = |
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.
Actually, could you do it the other way around? 🙏
The proper way is to have ZIOIdentityBoth
in AssociativeBoth
's companion object.
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.
Could you please move ZIOIdentityBoth
?
7fe3fda
to
b4df7ea
Compare
@@ -1200,14 +1200,6 @@ object AssociativeBoth extends LawfulF.Invariant[AssociativeBothDeriveEqualInvar | |||
def both[A, B](fa: => Vector[A], fb: => Vector[B]): Vector[(A, B)] = fa.flatMap(a => fb.map(b => (a, b))) | |||
} | |||
|
|||
/** |
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.
Did you mean to delete this?
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.
Yes, ZIOAssociativeBoth
can be fully replaced by ZIOIdentityBoth
. Or should we call it ZIOCommutativeIdentityBoth
? But it needs to be in the AssociativeBoth
companion object 😉
More detailed explanation here: https://meta.plasm.us/posts/2019/09/30/implicit-scope-and-cats/
* `AssociativeEither[G].both` operation, | ||
* returning `None` if the collection is empty. | ||
*/ | ||
def forany[G[+_]: AssociativeEither: Covariant, A, B](fa: F[A])(f: A => G[B]): Option[G[B]] = { |
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.
Isn't this collectFirst
? It applies the function f
to each element in the structure and returns the first result that is a "success", where the meaning of success and failure is defined by the AssociativeEither
instance?
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.
Yes, that's what I was going for! Thank you @adamgfraser , I didn't know it could have this name 👍
https://superruzafa.github.io/visual-scala-reference/collectFirst/ 👈 TIL
Although I would suspect we might need IdentityEither
for this.
I was pushed to make a proposal for it, when I was looking at the signature for foreach
and thought there should be a dual for it -- hence the name forany
.
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.
@sideeffffect Wow! That Visual Scala resource is really cool!
I think we can get away with just having an AssociativeEither
instance because None
can serve as the default value if the structure is empty or if there is no successful value. However, I think we need to flip the order of the result types here so we return a G[Option[B]]
. Otherwise we end up returning the last "failure" if the structure is non-empty and all of the results are failures.
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.
Yes. Good point! But in that case, we would probably need IdentityBoth
, to be able to create a G
of None
in case of an empty Traversable, right?
I've updated the ticket description #392
Please let me know, if you consider it accurate now 🙏
* `CommutativeEither[G].both` operation, | ||
* returning `None` if the collection is empty. | ||
*/ | ||
def foranyPar[G[+_]: CommutativeEither: Covariant, A, B](fa: F[A])(f: A => G[B]): Option[G[B]] = { |
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.
collectFirstPar
?
* Compute each element of the collection | ||
* with specified effectual function `f` | ||
* and then reduces the results using the | ||
* `AssociativeEither[G].both` operation, |
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.
* `AssociativeEither[G].both` operation, | |
* `AssociativeEither[G].either` operation, |
* Compute each element of the collection | ||
* with specified effectual function `f` | ||
* and then reduces the results using the | ||
* `CommutativeEither[G].both` operation, |
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.
* `CommutativeEither[G].both` operation, | |
* `CommutativeEither[G].either` operation, |
/** | ||
* Failing assertion, used for unexpected cases | ||
*/ | ||
val unexpectedResult: Assertion[Any] = |
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.
There is an existing nothing
assertion that you can use for this.
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.
Couple of suggestions on naming. Otherwise looks great! Thanks for all your work on this!
#392