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

MTL-style doesn't seem to work in Scala #1110

Open
puffnfresh opened this issue Feb 24, 2016 · 7 comments
Open

MTL-style doesn't seem to work in Scala #1110

puffnfresh opened this issue Feb 24, 2016 · 7 comments

Comments

@puffnfresh
Copy link
Member

Let's say you're trying to write methods which uses MTL-style classes such as MonadError and MonadReader. Good job!

But if you go to use more than one constraint on a method, you get ambiguous implicits:

scala> import scalaz._
import scalaz._

scala> import scalaz.syntax.monad._
import scalaz.syntax.monad._

scala> def x[F[_], A](implicit E: MonadError[F, Int], R: MonadReader[F, String]) = R.ask.flatMap(E.raiseError(_.length))
<console>:13: error: ambiguous implicit values:
 both value R of type scalaz.MonadReader[F,String]
 and value E of type scalaz.MonadError[F,Int]
 match expected type scalaz.Bind[F]
       def x[F[_], A](implicit E: MonadError[F, Int], R: MonadReader[F, String]) = R.ask.flatMap(E.raiseError(_.length))
                                                                                     ^

The problem is that both MonadError and MonadReader extend Monad, so there's 2 possible instances to choose from. They should be consistent with each-other, but scalac doesn't know that.

What can we do about this problem?

@jbgi
Copy link
Member

jbgi commented Feb 24, 2016

#1084

@shajra
Copy link

shajra commented Feb 24, 2016

I think we need to think about what can be done in 7.2, and what really needs to wait for 8.0.

If we decoupled the Monad instance, we've got a naming problem. Reader is taken. Maybe just Read? Could we do that for 7.2? That along with @jedws's fix of the kinds for these MT classes should make monad transformers much more usable in Scala. Throw in optics, and we might even have something fancy.

@aloiscochard
Copy link
Contributor

@puffnfresh as pointed out by @jbgi this problem is solved with the scato encoding.

@aloiscochard
Copy link
Contributor

@shajra I would love to see MTL+lens try out in scala, I wonder how that would look! and how usable that would be.

@shajra-cs
Copy link

Shucks, 7.2.0 is formally released, I forgot. I think technically, then, this change needs to be put in Scala 7.3.x?

@puffnfresh
Copy link
Member Author

@jbgi @aloiscochard wow, I didn't know this was fixed on that branch. Awesome work.

@adelbertc
Copy link
Contributor

Just found this issue after a random walk of Scalaz tickets, and I've been annoyed by this a lot recently.

Is it possible to do some sort of fix for this in the current subtype encoding? I think what @shajra was suggesting is something like:

trait MonadReader[F[_], R] { deps: Monad[F] =>
  ...
}

that way you avoid the ambiguous implicits, but at use site you do need to do something like:

// Note the need to require `Monad[F]` despite `MonadReader` being asked for
def foo[F[_]](implicit F: Monad[F], R: MonadReader[F, Int]) = ...

I bought this up in this thread where @aloiscochard brought up a good point about not being able to get Monad[F] given just MonadReader[F, _]. The proposal is to add a method to the type class to get it back out, like

trait MonadReader[F[_], R] { deps: Monad[F] =>
  def self: Monad[F]
  ...
}

This is basically the (very fascinating) Scato/Scalaz8 encoding to type classes minus the templating machinery, but plays nice with the current subtyping approach. The one thing that bothers me is this sort of treats the MTL type classes as special - for instance, you run into a similar issue with:

def foo[F[_]](implicit T: Traverse[F], A: Applicative[F]) = ...

because both Traverse and Applicative give a Functor. But I think it would be awkward to do this encoding for that hierarchy. In Scato/Scalaz8 this isn't a problem since everything is encoded this way so it's all consistent.

I'm mostly just looking for a solution in the subtyping encoding - the only downside I can see is we're special casing MTL. But other than that, does anyone have other proposals/suggestions/concerns around this approach?

adelbertc added a commit to adelbertc/scalaz that referenced this issue Sep 6, 2016
adelbertc added a commit to adelbertc/scalaz that referenced this issue Sep 8, 2016
adelbertc added a commit to adelbertc/scalaz that referenced this issue Sep 16, 2016


For posterity, this is the original PR that I closed before deciding
on the encoding you see before you:
scalaz#1254
adelbertc added a commit to adelbertc/scalaz that referenced this issue Sep 16, 2016


For posterity, this is the original PR that I closed before deciding
on the encoding you see before you:
scalaz#1254
adelbertc added a commit to adelbertc/scalaz that referenced this issue Sep 16, 2016


For posterity, this is the original PR that I closed before deciding
on the encoding you see before you:
scalaz#1254
adelbertc added a commit to adelbertc/scalaz that referenced this issue Sep 17, 2016


For posterity, this is the original PR that I closed before deciding
on the encoding you see before you:
scalaz#1254
adelbertc added a commit to adelbertc/scalaz that referenced this issue Sep 17, 2016


For posterity, this is the original PR that I closed before deciding
on the encoding you see before you:
scalaz#1254
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants