Skip to content

Instantly share code, notes, and snippets.

@pshirshov
Last active November 3, 2018 13:35
Show Gist options
  • Save pshirshov/1273add00d902a6cfebd72426d7ed758 to your computer and use it in GitHub Desktop.
Save pshirshov/1273add00d902a6cfebd72426d7ed758 to your computer and use it in GitHub Desktop.
Polymorphic abstract modules in Scala: projections and path-dependant types equality can't be proven
import scala.languageFeature.higherKinds
import scala.languageFeature.implicitConversions
trait IORunner[IO[+_]] {
def run[T](io: IO[T]): T
}
trait Point[IO[+_]] {
def point[T](v: T): IO[T]
}
trait Context {
type IO[+T]
implicit def runner: IORunner[IO]
implicit def point: Point[IO]
trait Aux[NIO[+_]] extends Context{
override type IO[+T] = NIO[T]
}
final class IMPL[C <: Context] extends Aux[C#IO] {
override implicit def runner: IORunner[IO] = Context.this.runner.asInstanceOf[IORunner[IO]]
override implicit def point: Point[IO] = Context.this.point.asInstanceOf[Point[IO]]
}
object IMPL {
def apply[C <: Context]: IMPL[C] = new IMPL[C]
}
final type DECL = this.type
def self: IMPL[DECL] = IMPL.apply[DECL]
}
trait Super[IO[+_]] {
def doSmth(): IO[Int]
}
class Component[C <: Context](val c: C#IMPL[C]) extends Super[C#IO] {
import c._
override def doSmth(): C#IO[Int] = implicitly[Point[IO]].point(1)
def runSmth(): Int = {
implicitly[IORunner[c.IO]].run(doSmth())
}
}
object OptionContext extends Context {
override type IO[+T] = Option[T]
override implicit def point: Point[Option] = new Point[Option] {
override def point[T](v: T): Option[T] = Option(v)
}
override implicit def runner: IORunner[Option] = new IORunner[Option] {
override def run[T](io: Option[T]): T = io.get
}
}
object App {
def main(args: Array[String]): Unit = {
val component = new Component(OptionContext.self)
println(component.runSmth())
}
}
// App.main(Array.empty) ==> 1
import scala.languageFeature.higherKinds
import scala.languageFeature.implicitConversions
trait IORunner[IO[+_]] {
def run[T](io: IO[T]): T = ???
}
trait Context {
type IO[+T]
implicit def runner: IORunner[IO] = ???
}
class Super[IO[+_]] {
def doSmth(): IO[Int] = ???
}
class Component[C <: Context](val c: C) extends Super[C#IO] {
import c._
def x(): Int = {
val io: C#IO[Int] = doSmth()
// c.IO != C#IO
implicitly[IORunner[IO]].run(io)
implicitly[IORunner[C#IO]].run(io)
}
}
import scala.languageFeature.higherKinds
import scala.languageFeature.implicitConversions
trait IORunner[IO[+_]] {
def run[T](io: IO[T]): T = ???
}
trait Context {
type IO[+T]
implicit def runner[IO[+_]]: IORunner[IO] = ???
trait Aux[NIO[+_]] extends Context{
override type IO[+T] = NIO[T]
}
type IMPL[C <: Context] = Aux[C#IO]
}
trait Super[IO[+_]] {
def doSmth(): IO[Int] = ???
}
class Component[C <: Context](val c: C#IMPL[C]) extends Super[C#IO] {
import c._
def runSmth(): Int = {
implicitly[IORunner[c.IO]].run(doSmth())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment