Add Foldable, Traverse and Comonad instances to WriterT#2182
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2182 +/- ##
==========================================
- Coverage 94.75% 94.73% -0.03%
==========================================
Files 330 330
Lines 5568 5582 +14
Branches 201 204 +3
==========================================
+ Hits 5276 5288 +12
- Misses 292 294 +2
Continue to review full report at Codecov.
|
|
I’m surprised this passes binary compatibility, but assuming that’s correct I’m +1 |
| def show(implicit F: Show[F[(L, V)]]): String = F.show(run) | ||
|
|
||
| def foldLeft[C](c: C)(f: (C, V) => C)(implicit F: Foldable[F]): C = | ||
| F.foldLeft(run, c)((z, v) => f(z, v._2)) |
There was a problem hiding this comment.
Can we call v instead lv here to remind us it has the written value?
There was a problem hiding this comment.
Sure thing, thanks
| F.foldLeft(run, c)((z, v) => f(z, v._2)) | ||
|
|
||
| def foldRight[C](lc: Eval[C])(f: (V, Eval[C]) => Eval[C])(implicit F: Foldable[F]): Eval[C] = | ||
| F.foldRight(run, lc)((v, z) => f(v._2, z)) |
There was a problem hiding this comment.
Can we call v as lv here too?
|
@johnynek not sure why it passes, I'm refreshing right now the rules of binary compatibility. What's the change here that you are not 100% sure about ? Because I might work it around even if it passes. Thanks for the help. |
| implicit val L0: Monoid[L] = L | ||
| } | ||
|
|
||
| implicit def catsDataFoldableForWriterT[F[_], L, V](implicit F: Foldable[F]): Foldable[WriterT[F, L, ?]] = |
There was a problem hiding this comment.
The Traverse instance is more specific and thus should have a higher priority than the Foldable instance.
In case you are curious, here is the guideline in this regard.
https://typelevel.org/cats/guidelines.html#a-idimplicit-priority-hrefimplicit-prioritya-implicit-instance-priority
I guess you can leave the instance of Traverse where you have now and move the Foldable instance down to WriterTInstance1
There was a problem hiding this comment.
thanks, makes perfectly sense. I wasn't sure about the precedence there, I should have read the guidelines myself. I'm changing it.
|
I believe the renaming of package private classes is binary compatible. If that's what @johnynek was referring to. |
|
Thank you lads for helping through the process. 👍 |
|
Considering that this is still open I would add the |
|
Sounds good :) |
Foldable, Traverse and Comonad instances to WriterT
|
@barambani , I took the liberty to update the PR title, if you don't mind. |
|
Thanks for doing it. I will also make the description more accurate |
|
Can you add resolution tests for |
|
And thanks a lot by the way. This is great! |
|
You're right, that's not resolved. I'm adding the tests and the fix. Thanks a lot |
|
Just for my understanding, could you point me to some details about why scalac fails to summon |
| implicit val L0: Monoid[L] = L | ||
| } | ||
|
|
||
| implicit def catsDataTraverseForWriterTId[L](implicit F: Traverse[Id]): Traverse[WriterT[Id, L, ?]] = |
There was a problem hiding this comment.
@barambani you can't have any instance that potentially conflicts in the same trait level.
I think there is Functor instance conflict here for [WriterT[Id, L, ?]. I think you might need to create quite a few more priority layers to separate the instances.
There was a problem hiding this comment.
to be clear I didn't see the actually error message on travis. But I think separating them out might solve the problem.
There was a problem hiding this comment.
Sorry for the confusion, my bad for the lack of clarity. This prioritisation should work (let's see when the CI completes). My question was more in general about the reason why we needed to create instances for Id. I would have expected that something like Comonad[WriterT[Id, ListWrapper[Int], ?]] could summon the instance for F[_] and I was wondering if you had resources about why that's not the case.
This doesn't mean that I'm not happy to add more priority levels if you think that's better. Thanks for the great help here.
There was a problem hiding this comment.
@barambani I don't know the underlying reason that Id needs to be special-cased, but it's a weakness in scalac's type inference. This is a related Stack Overflow post that I've seen before. Something like Id might be a tricky one because A =:= Id[A] =:= Id[Id[A]], so there may be some logic to short-circuit inference when applying a type results in the same type so you don't end up in an infinite loop or something. This is pure speculation :)
There was a problem hiding this comment.
@ceedubs thanks a lot, I didn't want for you to waste time on this. I was just taking advantage of this discussion in case you knew it out of your head 😃 👍
ceedubs
left a comment
There was a problem hiding this comment.
👍 LGTM thanks a lot, @barambani!
peterneyens
left a comment
There was a problem hiding this comment.
Thanks @barambani, I left two small comments.
| def foldRight[A, B](fa: WriterT[F, L, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = fa.foldRight(lb)(f) | ||
| } | ||
|
|
||
| private[data] sealed trait WriterTTraverse[F[_], L] extends Traverse[WriterT[F, L, ?]] with WriterTFoldable[F, L] { |
There was a problem hiding this comment.
If you extends WriterTFunctor here as well, you get its map implementation instead of the default traverse[Id] from Traverse.
There was a problem hiding this comment.
I will change it thanks 👍
|
|
||
| def traverse[G[_], V1](f: V => G[V1])(implicit F: Traverse[F], G: Applicative[G]): G[WriterT[F, L, V1]] = | ||
| G.map( | ||
| F.traverse(run)(lv => G.product(G.pure(lv._1), f(lv._2))) |
There was a problem hiding this comment.
Can this be G.tupleLeft(f(lv._2), lv._1) instead of G.product(G.pure(lv._1), f(lv._2))?
There was a problem hiding this comment.
sure changing it 👍
|
|
||
| override implicit def F0: Traverse[F] | ||
|
|
||
| override def map[A, B](fa: WriterT[F, L, A])(f: A => B): WriterT[F, L, B] = super[WriterTFunctor].map(fa)(f) |
There was a problem hiding this comment.
I think we can omit this line if we defined map in WriterTFunctor as override def map.
See for example EitherTFunctor and EitherTMonad (although EitherTTraverse doesn't extends EitherTFunctor at the moment and neither does OptionTTraverse OptionTFunctor).
There was a problem hiding this comment.
Very true, apologies. I'm fixing it. I rushed it in. I have to stop reading those intellij errors. Do you think I should change also EitherTTraverse and OptionTTraverse accordingly ?
There was a problem hiding this comment.
I think there are probably more cases than just EitherTTraverse and OptionTTraverse which can be improved, I would leave those for another PR.
peterneyens
left a comment
There was a problem hiding this comment.
Thanks again @barambani (and for the quick follow up on my nitpicking).
This adds
Foldable,TraverseandComonadinstances for WriterT. The relevant issue is #620