Skip to content
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

contramap on Function1 broke between 0.9 to 1.0.0-MF #1850

Closed
coltfred opened this issue Aug 23, 2017 · 6 comments
Closed

contramap on Function1 broke between 0.9 to 1.0.0-MF #1850

coltfred opened this issue Aug 23, 2017 · 6 comments
Assignees
Labels
Milestone

Comments

@coltfred
Copy link
Contributor

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

@durban
Copy link
Contributor

durban commented Aug 24, 2017

In 0.9.0 it works due to Unapply, in particular Unapply.catsUnapply2left (note the left).

@fthomas
Copy link
Member

fthomas commented Aug 24, 2017

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)))
)

@durban
Copy link
Contributor

durban commented Aug 25, 2017

Yes, that's a useful thing to know; although I've used -Xprint:typer 😄

@kailuowang
Copy link
Contributor

kailuowang commented Aug 30, 2017

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.

  1. document this limitation of partial unification in cats type class syntax and have our users use the work around above.
  2. bring Unapply back for this kind of right to left unification scenarios (anything else other than this one)?

What do you guys think?

@edmundnoble
Copy link
Contributor

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.

@kailuowang
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants