-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Implement several Functor methods to avoid using map when not needed #4801
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
Conversation
|
I couldn't find the native error. I guess is may be some issue with the native being flakey? I can't see why the changes would fail on native but not JVM. |
danicheg
left a comment
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.
Adding some tests would be nice. Anyway, LGTM
I've added some tests. Ideally these would be added to FunctorLaws saying that those methods need to match the map based implementations. Doing that, however, would break compatibility of FunctorLaws because it requires more Honestly, I wonder if the laws need some higher kinded change. Something like |
|
@danicheg how does this look? I think it is ready to merge. |
| } | ||
| override def distribute[F[_], A, B](fa: F[A])(f: A => B)(implicit F: Functor[F]): Id[F[B]] = F.map(fa)(f) | ||
| override def map[A, B](fa: A)(f: A => B): B = f(fa) | ||
| override def as[A, B](fa: A, b: B): B = 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.
I wonder – should we get void here for completeness? As long as as is here.
|
@johnynek I totally agree that ideally these tests should be covered in the Laws. However, since it not feasible to achieve it easily, wouldn't it make sense to generalize them anyway. E.g. something like this: trait FunctorSuiteBase { self: CatsSuite =>
def testMapBasedImplementations[F[_]: Functor](implicit
arbFI: Arbitrary[F[Int]], arbFIS: Arbitrary[F[(Int, String)]],
eqFU: Eq[F[Unit]], eqFI: Eq[F[Int]], eqFS: Eq[F[String]], eqFIS: Eq[F[(Int, String)]], eqFSI: Eq[F[(String, Int)]], eqFIL: Eq[F[(Int, Long)]], eqFLI: Eq[F[(Long, Int)]]
): Unit =
test("functor default methods match map-based implementations") {
val F = Functor[F]
forAll { (fa: F[Int], b: String, f: Int => Long) =>
assert(F.as(fa, b) === F.map(fa)(_ => b))
assert(F.tupleLeft(fa, b) === F.map(fa)(a => (b, a)))
assert(F.tupleRight(fa, b) === F.map(fa)(a => (a, b)))
assert(F.fproduct(fa)(f) === F.map(fa)(a => (a, f(a))))
assert(F.fproductLeft(fa)(f) === F.map(fa)(a => (f(a), a)))
assert(F.void(fa) === F.map(fa)(_ => ()))
}
forAll { (fab: F[(Int, String)]) =>
assert(F.unzip(fab) === (F.map(fab)(_._1), F.map(fab)(_._2)))
}
}
}and then call All these new tests look so identical that I couldn't help but suggest it out :) |
|
@satorg I've added For instance, what if we add more map-based methods we'd like to test, but they require more implicits than the ones we add to that trait? Ideally we would have a clean story to add laws to the original FunctorLaws, (such as the higher kinded Arbitrary and Eq suggestion I made). Really we want something like trait Higher[F[_], G[_]] {
def lower[A](f: F[A]): F[G[A]]
}Then we would have these laws be given class TestType {
type T
def arbT: Arbitrary[T]
def eqT: Eq[T]
def cogenT: Cogen[T]
}
class TestTypeK {
type T[_]
def arbT: Higher[Arbitrary, T]
def eqT: Higher[Eq, T]
def cogenT: Higher[Cogen, T]
}with this, I think maybe all laws on In any case, I think this is way beyond the scope of this PR. Can we punt the abstraction of tests and just merge this relatively simple improvement to map-based functor methods for these small common types? |
satorg
left a comment
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!
I reached for tupleLeft in this PR:
typelevel/cats-collections#779
But then looked and noticed that actually it and related functions haven't been overridden in many places. This PR addresses that.