-
-
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
Replace TransLift with MonadTrans #1621
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1621 +/- ##
==========================================
- Coverage 93.37% 93.33% -0.04%
==========================================
Files 240 241 +1
Lines 3937 3948 +11
Branches 138 135 -3
==========================================
+ Hits 3676 3685 +9
- Misses 261 263 +2
Continue to review full report at Codecov.
|
This gets a 👍 from me. I think recent efforts really prove that we weren't gaining anything from the flexibility of |
CI on 2.11.8 fails due to "The job exceeded the maximum time limit for jobs, and has been terminated.". Using coursier may chop off some build time. |
/** | ||
* A type class which abstracts over the ability to lift an M[A] into a | ||
* MonadTransformer | ||
*/ |
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.
nit here: the scala doc style in cats is
/**
*
*/
i.e. all stars aligned with the first star.
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.
other than that it's a 👍 from me.
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.
fixed
trait MonadTrans[MT[_[_], _]] { | ||
/** | ||
* Lift a value of type M[A] into a monad transformer MT[M, A] | ||
*/ |
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.
And this one. also maybe a blank line above?
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.
haven't noticed 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.
LGTM. Thanks very much!
Does anyone know of any data structures that require |
@ceedubs |
Apparently |
@wedens I don’t think @ceedubs Is there anything other than @typeclass trait PointedK[F[_[_], _]] extends MonadTrans[F] {
def pointk[G[_]: Functor]: G ~> F[G, ?]
def liftT[M[_]: Monad, A](ma: M[A]) = pointk[M].apply(ma)
} (ok, maybe we have to deal with the natural transformation somehow, but you get the gist). Right now, And the underlying need for |
@sellout I'm pretty sure you can't define |
@djspiewak Maybe (I think – again, not sure – you only need Applicative), but that doesn’t mean you can’t |
@sellout Oh, you're right. The implementation of |
I’m going to frame that comment. |
} | ||
|
||
final class MonadTransOps[F[_], A](val fa: F[A]) extends AnyVal { | ||
def liftT[MT[_[_], _]](implicit F: Monad[F], MT: MonadTrans[MT]): MT[F, A] = |
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.
How about a doctest here? It will provide coverage for both here and the syntax line above. Then you should get green light from codecov
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 a test in SyntaxTests
.
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 pointed out because codecov reported test miss here. Now I see that SyntaxTest
is only a compilation check. I think I prefer a doctest in the type class which actually run the code (thus coverage) and provide a concrete example there. But we can certainly address that in a different PR.
*/ | ||
sealed trait Trivial | ||
|
||
object Trivial { |
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 understand that as a result of this PR Trivial
is no longer needed in cats, but it is still a very useful type constraint. Is there a good reason to remove Trivial
?
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 thought about making the same objection, but my conclusion was that "less is more" in terms of API surface area. Shapeless already has a Trivial
, and it is very likely to be on the classpath of anyone who needs this sort of thing. I don't think there's a need for cats to keep 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.
We are also going to remove unapply
to a separate module. Maybe we should copy trivial there too?
@@ -39,7 +39,7 @@ trait AllSyntax | |||
with ShowSyntax | |||
with SplitSyntax | |||
with StrongSyntax | |||
with TransLiftSyntax | |||
with MonadTransSyntax |
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.
Keep in alphabetical order?
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.
ok
/** | ||
* Lift a value of type M[A] into a monad transformer MT[M, A] | ||
*/ | ||
def liftT[M[_]: Monad, A](ma: M[A]): MT[M, A] |
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.
One thing Edward Kmett noted in a talk he gave on monad homomorphisms is that MonadTrans
provides no constraint that the resulting MT[M, A]
has a Monad
instance. I believe in his talk he fixes this by adding a function taking the Monad[M]
constraint and providing a Monad[MT[M, ?]]
constraint. In Scala it might look something like:
implicit def mtMonad[M[_]: Monad]: Monad[MT[M, ?]]
Would we want something like that here?
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.
scalaz does it. Not sure if it's useful. But it makes sense in theory.
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 would communicate the law: For every lawful M[_]: Monad
there exists a lawful MT[M, ?]: Monad
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.
Can we check such a law? Would be cool if we could rule out the naïve ListT
for 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.
A simple way would be to pick a fixed M
, e.g. Option
, get the Monad[MT[Option, ?]]
from this method, and then law-check that.
A fancier way would be to use existentials or something to be able to vary M
and do law-checking across all these :-)
EDIT Hmm I actually don't know what that would look like in terms of code though.
Should we merge this as is and add an eventual |
Note: https://github.com/milessabin/kittens/pull/37 to move |
is there something holding this PR? |
@wedens I just thumbed up @peterneyens's last comment. @adelbertc what do you think? If you have no issue with that, I think this one is good to merge. |
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.
LGTM.
While it took a while, I'm sold on the fact that One thing that I didn't realize at first and that I haven't seen come up in comments (other than the original PR description) is that here, |
@tpolecat @edmundnoble @djspiewak are you still happy with this PR in response to #1621 (comment) ? I'm definitely not opposed to this PR being merged, but I respect others' opinion on this much more than my own, because I only rarely use |
I think we may need to change the |
Uh, am I missing something? |
@djspiewak oops I had |
Wait that makes sense that |
Okay this has 3 signoffs. I'm going to go ahead and merge it. |
Oops I had forgotten about #1621 (comment) . I can't take care of it at the moment. I should be able to do it this evening if nobody beats me to it. |
@wedens Just so you know, cats-mtl has its own formulation of |
Resolves #1613.
Pros:
MonadTrans
is lawful (well... almost). There are identity (liftT . pure = pure
) and composition (liftT (m >>= f) = liftT m >>= (liftT . f)
) laws. I think forMonadTrans
to be really lawful it should extend (in current encoding)Monad
. But it will make it unusable for the same reasonMonadError
et al is (diamonds 💎 )Cons:
Monad
constraint is imposed on for any base functor. For some transformers (e.g.Kleisli
)liftT
can be implemented with weaker constraint/cc @djspiewak @ceedubs