In cats 0.9 you could call .contramap on a Function1[A,R]. In 1.0.0-MF it no longer works. @sellout hypothesised that there might have been an explicit method on Function1Ops.
Discussion happened here: https://gitter.im/typelevel/cats?at=599dfc7e19147ac32315dcc7
In 0.9.0 it works due to Unapply, in particular Unapply.catsUnapply2left (note the _left_).
For those wondering how @durban figured out that it worked with Unapply.catsUnapply2left, here's one way he could have done that: :-)
scala> scala.reflect.runtime.universe.reify {
((_: Int).toString).contramap((_: Int) * 2)
}
res0: reflect.runtime.universe.Expr[Int => String] = Expr[Int => java.lang.String](
`package`.contravariant.catsSyntaxUContravariant(((x$1: Int) => (x$1: Int).toString()))(
Unapply.catsUnapply2left(`package`.function.catsStdContravariantForFunction1)
).contramap(((x$2: Int) => (x$2: Int).$times(2)))
)
Yes, that's a useful thing to know; although I've used -Xprint:typer :smile:
This is due to the fact that the Contravariant syntax no longer works on Function1[?, B] under the partial unification SI-2712 fix ( a replacement for the removed Unapply mechanism)
The partial unification fix has one limitation over Unapply, it only support left-to-right partial order. In the Contravariant of Function1[?, B] case, the left-to-right order no longer applies.
The immediate work around is to use the Contravariant type class directly instead of the syntax. I.e. the following works
Contravariant[? => B].contramap(f)(...)
Update: as suggested by @edmundnoble below lmap from Profunctor is a better alternative.
I see a couple of options ahead.
Unapply back for this kind of right to left unification scenarios (anything else other than this one)? What do you guys think?
I'd say 1. is our best option here. Unapply has a huge cost in compilation time and doesn't scale to different arities. In general, the story for type classes in multiple type parameters is bad, in every functional programming language I know of. Afaik the best solution for now is to just need a type class which combines every type class for every type parameter of the type constructor, like in this case Profunctor, specifically using lmap.
sort of fixed by #1937 , i.e. we are not going to make any change to the code, instead @LukaJCB provided a scalafix to help people migrate to lmap which has better type inference.
Most helpful comment
I'd say 1. is our best option here. Unapply has a huge cost in compilation time and doesn't scale to different arities. In general, the story for type classes in multiple type parameters is bad, in every functional programming language I know of. Afaik the best solution for now is to just need a type class which combines every type class for every type parameter of the type constructor, like in this case Profunctor, specifically using
lmap.