Open edmundnoble opened 6 years ago
Interesting. Shims isn't providing the instance itself, but it's hard to say for sure. Id
is basically just a terrible type to be using in these sorts of cases because of aliasing issues in scalac, but it definitely shouldn't be broken by shims. I'll take a look.
Interesting that BindRec[Id]
materializes just fine…
scala> import scalaz._, Scalaz._, shims._
import scalaz._, Scalaz._, shims._
<console>:11: warning: Unused import
import scalaz._, Scalaz._, shims._
^
<console>:11: warning: Unused import
import scalaz._, Scalaz._, shims._
^
import scalaz._
import Scalaz._
import shims._
scala> Monad[Id]
Monad[Id]
<console>:20: error: ambiguous implicit values:
both method flatMapToScalaz in trait FlatMapConversions of type [F[_]](implicit FC: shims.util.Capture[cats.FlatMap[F]])scalaz.BindRec[F] with shims.conversions.Synthetic
and value idInstance in package scalaz of type => scalaz.Traverse1[scalaz.Id.Id] with scalaz.Monad[scalaz.Id.Id] with scalaz.BindRec[scalaz.Id.Id] with scalaz.Comonad[scalaz.Id.Id] with scalaz.Distributive[scalaz.Id.Id] with scalaz.Zip[scalaz.Id.Id] with scalaz.Unzip[scalaz.Id.Id] with scalaz.Align[scalaz.Id.Id] with scalaz.Cozip[scalaz.Id.Id] with scalaz.Optional[scalaz.Id.Id]
match expected type scalaz.BindRec[scalaz.Scalaz.Id]
val res0 =
^
scala> Monad[Lambda[X => X]]
Monad[Lambda[X => X]]
<console>:13: warning: Unused import
import Scalaz._
^
res1: scalaz.Monad[[X]X] = scalaz.IdInstances$$anon$1@4037c5b8
It's an aliasing issue.
It appears that some witchcraft is summoning cats.catsInstancesForId
despite not having been imported. I really don't know what could be causing this other than a bug in scalac.
I figured it out. Both scalaz and cats Id
type gets automagically summoned instances. Behold:
scalaz.Monad[scalaz.Id.Id]
cats.Monad[cats.Id]
Both those lines compile with no imports. So this is why things are ambiguous: both monads are in scope, and shims makes them equivalent.
But, "how?!" you ask. Good question, intrepid reader! This gist shows a condensed example of the phenomenon in play here: https://gist.github.com/8680f463d4e2e4a8aa8a9e0bb7999ce0 The implicit scope for resolving a given type includes all companions of components of the type. As it turns out, one of the components of a type is the package itself, and the package object is considered part of the package scope. As you may recall from Shapeless's Poly
, objects are their own companions, and package objects are objects (mostly). So in other words, the fact that both scalaz and cats put their idInstance
implicits into the package prevents us from eliminating those instances from scope.
I would consider this to be a pretty significant design flaw in both frameworks, but in fairness, this is a really really obscure corner of implicit scoping.
In the meantime, I'm not really sure if there's anything shims can do here. In theory, I'd really like shims implicits to be "magically lowest" priority in that they are only selected when no other implicits are applicable, but I don't have a handy trick for achieving that.
To reproduce:
Result:
First encountered on shims 1.1, upgraded to shims 1.2.1 where the problem persisted. Scalaz version 7.2.17, no cats imports.
EDIT: Worked around by shadowing
idInstance
in the scope where it's used. Perhaps shims is providing the instance itself somehow?