-
-
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
Add mapK to transformers #1987
Add mapK to transformers #1987
Conversation
This is great! Thanks for this. :) You do have some conflicts though. I also left a couple of tiny comments. |
@@ -234,4 +234,3 @@ private[data] trait EitherKComonad[F[_], G[_]] extends Comonad[EitherK[F, G, ?]] | |||
def extract[A](p: EitherK[F, G, A]): A = | |||
p.extract | |||
} | |||
|
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.
This is by accident?
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.
That's Emacs doing some extra housekeeping from having the file open. I'll revert it.
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.
Also-- you're fast! This PR was up for just a few minutes and you were already on top of it 😄.
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.
Haha, yeah, sorry for nitpicking so quickly 😄
@@ -18,8 +18,11 @@ final case class Kleisli[F[_], A, B](run: A => F[B]) { self => | |||
def map[C](f: B => C)(implicit F: Functor[F]): Kleisli[F, A, C] = | |||
Kleisli(a => F.map(run(a))(f)) | |||
|
|||
def mapF[N[_], C](f: F[B] => N[C]): Kleisli[N, A, C] = | |||
Kleisli(run andThen f) |
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.
Maybe we can keep this as a deprecated alias? :)
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 didn't mean to remove it-- I had added mapF
to every transformer but wound up splitting off mapK
additions to a separate PR. This just an accidental carry over from the split!
52cb546
to
208fbd0
Compare
208fbd0
to
5fca942
Compare
Oh and can you also add it to |
FreeT already has |
Codecov Report
@@ Coverage Diff @@
## master #1987 +/- ##
=========================================
- Coverage 96.21% 96.12% -0.1%
=========================================
Files 272 272
Lines 4627 4640 +13
Branches 115 117 +2
=========================================
+ Hits 4452 4460 +8
- Misses 175 180 +5
Continue to review full report at Codecov.
|
I've marked a few items as deprecated. If we'd like to keep the deprecation annotations, I'll need to know the release this PR is scheduled for and update them accordingly. |
Can we not have a typeclass here? Seems like we want the analog to Functor no? Any reason not to add with so many instances? The composition law is pretty obvious. Seems worth it to me. |
Definitely. There has been related discussion in the past, starting with #1713. I'd like to add a |
If we are adding mapK I think we should only do it if we also add that
FunctorK. I don’t think this should be controversial. Look at how many
instances there are.
On Sat, Oct 21, 2017 at 21:00 andy scott ***@***.***> wrote:
Definitely. There has been related discussion in the past, starting with
#1713 <#1713>.
I'd like to add a FunctorK in the same manner as @kailuowang
<https://github.com/kailuowang>'s mainecoon:
https://github.com/kailuowang/mainecoon/blob/master/core/src/main/scala/mainecoon/FunctorK.scala
.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#1987 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAEJdt_YM0sTNPJ7Sxqy4QxkTW8Egcmaks5suuf2gaJpZM4QBvO_>
.
--
P. Oscar Boykin, Ph.D. | http://twitter.com/posco | http://pobox.com/~boykin
|
https://github.com/andyscott/cats/pull/1/files has FunctorK and instances for OptionT and EitherT. If that looks good, I'll give the same treatment to the rest of the instances. A few notes on my implementation: For a given transformer, FunctorK is invariant with regards to all non-effect parameters and requires no additional evidence. At the value level, only one instance is needed-- so I use a cast to specialize for non-effect parameters. This can be switched to the traditional implementation if desired. There's no way easy way to provide arbitrary FunctionK transformations, so the laws for FunctorK just ask for specific transformations to test. In Mainecoon, laws ask for arbitrary instances but elsewhere |
There are two contention points IRT the type class,
On the other hand, both definitions of this type classes (
@andyscott what's your incentive for this to be in the same manner as in Update: In mainecoon, there is a use case for the |
I agree with @kailuowang that it's not very useful in general as a typeclass atleast for |
I originally just needed something similar to mapK to modify my transformer
stack with `F ~> F` transformations. Specifically I wanted an easier way to
call methods directly on Monix Tasks. This PR is the result of various
discussions related to that.
On Oct 23, 2017 09:25, "LukaJCB" <[email protected]> wrote:
I agree with @kailuowang <https://github.com/kailuowang> that it's not very
useful in general as a typeclass atleast for cats-core. The only reason I
could see, is that it might be useful for both cats-mtl and mainecoon which
both depend on cats-core, so they don't have to define their own separately.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1987 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAS8WxIhD2gprzkadqeqT-Dneq4U1VMrks5svL3mgaJpZM4QBvO_>
.
|
Quick reminder - |
@LukaJCB the need for a |
Ah you're right! In that case, my vote goes to merging it as is right now :) |
@iravid Yep. Everything except IRWST and IndexedStateT could have an instance if we add FunctorK. |
I think all feedback has been addressed. Codecov has failed the PR because the deprecated methods don't have coverage (they simply forward to |
@andyscott it can also be added to
@johnynek shall we unify the methods first in this PR and determine the type class later. There have been several attempts to add this |
@kailuowang I'll take care of them within the next day. |
I guess we can just copy this pattern all over. I kind of hate that in a library about typeclasses we are ignoring this. Also, I think it would compose in a nice way for the transformers. So, if you have Of course, the scala type system issues are a pain, so I guess if we don't have a clean way to write this typeclass we should punt. |
There have been discussions on having a see #1940 |
I'm actually -1 on tiny modules that we then have to bolt on a ton of boiler plate and imports.
The main motivations, in my view, for splitting modules are:
I really don't think there are significant reasons to split other than that. This does not seem to be one of those two cases. |
I'm also -1 on tiny modules for the same reasons. But if we can't add something to the core module and it's valuable, then having it in a tiny module is arguably better than not having it at all. |
We should continue the discussion here #1713. And like @kailuowang said we could potentially still add it if we come to a good conclusion. |
I've added missing instances. The remaining tests still need to be added. When adding the method to Free, I realized I have it set up so mapK on Free operates on the free functor |
λ[FunctionK[S, Free[T, ?]]](fa => Suspend(f(fa))) | ||
}(Free.catsFreeMonadForFree) | ||
*/ | ||
@deprecated("Use mapK", "1.0.0") |
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 am not sure if we want to deprecate this one. compile
seems a meaningful alias.
I am fine with |
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.
looks good. One minor comment.
@@ -218,10 +231,17 @@ object Free extends FreeInstances { | |||
pure(()).flatMap(_ => value) | |||
|
|||
/** | |||
* a FunctionK, suitable for composition, which calls mapK | |||
*/ | |||
def mapK[F[_], G[_]](fk: FunctionK[F, G]): FunctionK[Free[F, ?], Free[G, ?]] = |
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.
why FunctionK[F, G]
here but F ~> G
in most other places?
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.
This method is a copy-paste-rename from the original Free.compile
. I'll go through and switch FunctionK
to ~>
in the files modified by this PR, for consistency.
The Travis build fails because the |
Actually can we also not deprecate |
@andyscott we continued this in #2000 so that we can release this morning. Sorry for the rush. thanks for this awesome contribution. |
closing as #2000 is merged |
Adds
mapK
to the following:cats.data.EitherK
cats.data.EitherT
cats.data.Func
cats.data.IdT
cats.data.IndexedReaderWriterStateT
cats.data.IndexedStateT
cats.data.Kleisli
cats.data.Nested
cats.data.OneAnd
cats.data.OptionT
cats.data.Tuple2K
cats.data.WriterT
cats.free.Coyoneda
cats.free.Free
cats.free.FreeT
cats.free.Yoneda
The following are marked deprecated in favor of
mapK
:cats.data.Kleisli#transform
cats.free.Coyoneda#transform
cats.free.Free#compile
cats.free.Free.compile
cats.free.FreeT#hoist
The primary motivation for this is to allow easy (and consistent) access to the transformer's underlying effect. For example, given a computation
OptionT[Task, Int]
, you may want to call some of the underlying methods provided byTask
.