Created
September 20, 2016 10:18
-
-
Save b-studios/a09e9966778bcbd09a777f078ae822f3 to your computer and use it in GitHub Desktop.
Trying to help the compiler inferring type constructors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Default functor and monad TCs | |
trait Functor[F[_]] { | |
def map[A, B](fa: F[A], f: A => B): F[B] | |
} | |
trait Monad[M[_]] { | |
def unit[A](value: A): M[A] | |
def flatMap[A, B](ma: M[A], f: A => M[B]): M[B] | |
def map[A, B](ma: M[A], f: A => B): M[B] = flatMap(ma, f andThen unit) | |
} | |
def unit[A, M[_]: Monad](value: A): M[A] = implicitly[Monad[M]].unit(value) | |
// For type constructors with multiple arguments, such as | |
trait Foo[A, B] | |
// we can give monad instances, but they will not automatically be found by implicit resolution: | |
// (using kind projector syntax here) | |
implicit def monadFoo[A]: Monad[Foo[A, ?]] = ??? | |
// idea: have a typeclass that witnesses that a type is an application of a typeconstructor F to | |
// an argument A | |
trait App[X] { | |
type F[X] | |
type A | |
// these should not be too hard to provide :) | |
implicit val ev1: X =:= F[A] | |
implicit val ev2: F[A] =:= X | |
} | |
object App { | |
type Aux[X, FF[_], AA] = App[X] { type F[X] = FF[X]; type A = AA } | |
} | |
// now for providing monad ops as syntax, we just require that X is a type constructor | |
// application and app.F is a monad. | |
implicit class MonadOps[X](ma: X)(implicit val app: App[X]) { | |
import app._ | |
def flatMap[B](f: A => F[B])(implicit m: Monad[F]): F[B] = m.flatMap(ma, f) | |
def map[B](f: A => B)(implicit m: Monad[F]): F[B] = m.map(ma, f) | |
} | |
implicit def appFoo[A, B]: App.Aux[Foo[A, B], Foo[A, ?], B] = ??? | |
// However, as it turns out, this is not enough... | |
val foo: Foo[Int, String] = ??? | |
// ... since we loose type information in the inferred argument `app`: | |
// val app = implicitly[App[Foo[Int, String]]] | |
// which is the same as: | |
// val app: App[Foo[Int, String]] = appFoo[Int, String] | |
// but not the same as: | |
val app = appFoo[Int, String] | |
// for which we can prove (but cannot for the above two variants): | |
implicitly[app.A =:= String] | |
implicitly[app.F[String] =:= Foo[Int, String]] | |
val m = implicitly[Monad[app.F]] | |
// but even then this is not enough: | |
// | |
// [error] test.scala:60: type mismatch; | |
// [error] found : Monad[app.F] | |
// [error] required: Monad[_5.app.F] where val _5: MonadOps[Foo[Int,String]] | |
new MonadOps(f)(app).map[Int](x => ???)(m) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment