Принудительное разрешение зависимых типов для неявных вызовов - PullRequest
1 голос
/ 01 июля 2019

У меня есть черта обертки:


trait Wrapper[T] {

  ...
  type Own[F[_]] <: OwnThing[F]
  def ask[F[_]](implicit own: Own[F])

}

И различные реализации, вот пример:

class CombinedWrapper[A, B](wrapperA: Wrapper[A], wrapperB: Wrapper[B]) extends Wrapper[(A, B)] {
  override type Own[F[_]] = SomeOwnThing[(A, B), wrapperA.Own[F], wrapperB.Own[F]]
  override def ask[F[_]](implicit own: Own[F]) = ???
}

Но неявное разрешение не разрешает зависимые от пути типы, поэтому не обнаруживает никаких последствий.

Есть ли способ форсировать разрешение зависимых от пути типов? На данный момент я просто считаю их переменными, но на уровне типов.

Редактировать: Более полная версия:


trait Wrapper[T] {

  ...
  type Own[F[_]] <: OwnThing[F, T]
  def ask[F[_]](implicit own: Own[F])

}

sealed trait OwnThing[F[_], A]

trait SomeOwnThing[F[_], A, B, ThingA <: OwnThing[F, A], ThingB <: OwnThing[F, B]] extends OwnThing[F, (A, B)] {
  def underlyingA: ThingA
  def underlyingB: ThingB
}

class CombinedWrapper[A, B](wrapperA: Wrapper[A], wrapperB: Wrapper[B]) extends Wrapper[(A, B)] {
  override type Own[F[_]] = SomeOwnThing[F, A, B, wrapperA.Own[F], wrapperB.Own[F]]
  override def ask[F[_]](implicit own: Own[F]) = ???
}

Edit2: нерабочий пример

trait SimpleOwn[F[_], A] extends OwnThing[F, A]

class SimpleWrapper[T] extends Wrapper[T] {
    override type Own[F[_]] = SimpleOwn[F, T]
    override def ask[F[_]](implicit own: Own[F]) = ???
  }

val combined = new CombinedWrapper[String, Int](new SimpleWrapper[String], new SimpleWrapper[Int])
type Id[A] = A

//Simple case for base types
implicit val intOwn: SimpleOwn[Id, Int] = new SimpleOwn[Id, Int]
implicit val stringOwn: SimpleOwn[Id, String] = new SimpleOwn[Id, String]

//Should combine the two above
implicit def composeOwnIds[A, B, ThingA <: OwnThing[Id, A], ThingB <: OwnThing[Id, B]](implicit aOwn: ThingA, bOwn: ThingB): SomeOwnThing[Id, A, B, ThingA, ThingB] = new SomeOwnThing {
  override def underlyingA: ThingA = aOwn
  override def underlyingB: ThingB = bOwn
}

//Should work but cant find implicit
combined.ask[Id]

Edit3: для меня корень проблемы в CombinedWrapper в определении члена типа. Я думаю, что Scala не разрешает использование зависимых от пути типов в определении.

Я могу сказать это, потому что

new SimpleWrapper[String].ask

компилирует

1 Ответ

3 голосов
/ 04 июля 2019

Сначала исправьте несколько опечаток

//class CombinedWrapper[A, B](wrapperA: Wrapper[A], wrapperB: Wrapper[B]) extends Wrapper[(A, B)] {
  class CombinedWrapper[A, B](val wrapperA: Wrapper[A], val wrapperB: Wrapper[B]) extends Wrapper[(A, B)] { ...

//implicit val intOwn: SimpleOwn[Id, Int] = new SimpleOwn[Id, Int]
  implicit val intOwn: SimpleOwn[Id, Int] = new SimpleOwn[Id, Int] {}
//implicit val stringOwn: SimpleOwn[Id, String] = new SimpleOwn[Id, String]
  implicit val stringOwn: SimpleOwn[Id, String] = new SimpleOwn[Id, String] {}

//implicit def composeOwnIds[A, B, ThingA <: OwnThing[Id, A], ThingB <: OwnThing[Id, B]](implicit aOwn: ThingA, bOwn: ThingB): SomeOwnThing[Id, A, B, ThingA, ThingB] = new SomeOwnThing {
  implicit def composeOwnIds[A, B, ThingA <: OwnThing[Id, A], ThingB <: OwnThing[Id, B]](implicit aOwn: ThingA, bOwn: ThingB): SomeOwnThing[Id, A, B, ThingA, ThingB] = new SomeOwnThing[Id, A, B, ThingA, ThingB] { ...

Затем стандартным способом отладки имплицитов является их разрешение вручную (возможно, с явным указанием некоторых параметров типа) и просмотр ошибок компиляции.

new SimpleWrapper[String].ask
new SimpleWrapper[Int].ask

на самом деле

new SimpleWrapper[String].ask[Id](stringOwn)
new SimpleWrapper[Int].ask[Id](intOwn)

Если вы попытаетесь

combined.ask[Id](composeOwnIds(stringOwn, intOwn))

, у вас будет

Error: type mismatch;
 found   : App.intOwn.type (with underlying type App.SimpleOwn[App.Id,Int])
 required: App.combined.wrapperB.Own[App.Id]
Error: type mismatch;
 found   : App.stringOwn.type (with underlying type App.SimpleOwn[App.Id,String])
 required: App.combined.wrapperA.Own[App.Id]

Если вы попытаетесь

combined.ask[Id](composeOwnIds[String, Int, SimpleOwn[Id, String], SimpleOwn[Id, Int]](stringOwn, intOwn))

вы '

Error: type mismatch;
 found   : App.SomeOwnThing[App.Id,String,Int,App.SimpleOwn[App.Id,String],App.SimpleOwn[App.Id,Int]]
 required: App.combined.Own[App.Id]
    (which expands to)  App.SomeOwnThing[App.Id,String,Int,App.combined.wrapperA.Own[App.Id],App.combined.wrapperB.Own[App.Id]]

Если вы замените

val combined = new CombinedWrapper[String, Int](new SimpleWrapper[String], new SimpleWrapper[Int])

на

val strWrapper = new SimpleWrapper[String]
val intWrapper = new SimpleWrapper[Int]
val combined = new CombinedWrapper[String, Int](strWrapper, intWrapper)

, то

combined.ask[Id](composeOwnIds[String, Int, strWrapper.Own[Id], intWrapper.Own[Id]](stringOwn, intOwn))

даст

Error: type mismatch;
 found   : App.SomeOwnThing[App.Id,String,Int,App.strWrapper.Own[App.Id],App.intWrapper.Own[App.Id]]
    (which expands to)  App.SomeOwnThing[App.Id,String,Int,App.SimpleOwn[App.Id,String],App.SimpleOwn[App.Id,Int]]
 required: App.combined.Own[App.Id]
    (which expands to)  App.SomeOwnThing[App.Id,String,Int,App.combined.wrapperA.Own[App.Id],App.combined.wrapperB.Own[App.Id]]
  combined.ask[Id](composeOwnIds[String, Int, strWrapper.Own[Id], intWrapper.Own[Id]](stringOwn, intOwn))

Дело в том, что хотя combined.wrapperA равно strWrapper и combined.wrapperB равно intWrapper, но типы combined.wrapperA.Own[Id] и strWrapper.Own[Id] различны, а типы combined.wrapperB.Own[Id] и intWrapper.Own[Id] также различны.

Например, если у вас есть

trait MyTrait { type T }
val mt = new MyTrait {}
val mt1 = mt

, тогда значения равны, но типы различаются

//  implicitly[mt.T =:= mt1.T] // doesn't compile
//  implicitly[mt1.T =:= mt.T] // doesn't compile

Попробуйте изменить CombinedWrapper, добавив дополнительные параметры типа и указав ихс определенными зависимыми типами на сайте вызова

  trait Wrapper[T] {
    type Own[F[_]] <: OwnThing[F, T]
    def ask[F[_]](implicit own: Own[F])
  }

  sealed trait OwnThing[F[_], A]

  trait SomeOwnThing[F[_], A, B, ThingA <: OwnThing[F, A], ThingB <: OwnThing[F, B]] extends OwnThing[F, (A, B)] {
    def underlyingA: ThingA
    def underlyingB: ThingB
  }

//  class CombinedWrapper[A, B](val wrapperA: Wrapper[A], val wrapperB: Wrapper[B]) extends Wrapper[(A, B)] {
//    override type Own[F[_]] = SomeOwnThing[F, A, B, wrapperA.Own[F], wrapperB.Own[F]]
//    override def ask[F[_]](implicit own: Own[F]) = ???
//  }

  class CombinedWrapper[A, B, OwnA[F[_]] <: OwnThing[F, A], OwnB[F[_]] <: OwnThing[F, B]](
    val wrapperA: Wrapper[A] { type Own[F[_]] = OwnA[F] }, 
    val wrapperB: Wrapper[B] { type Own[F[_]] = OwnB[F] }
  ) extends Wrapper[(A, B)] {
    override type Own[F[_]] = SomeOwnThing[F, A, B, OwnA[F], OwnB[F]]
    override def ask[F[_]](implicit own: Own[F]) = ???
  }

  trait SimpleOwn[F[_], A] extends OwnThing[F, A]

  class SimpleWrapper[T] extends Wrapper[T] {
    override type Own[F[_]] = SimpleOwn[F, T]
    override def ask[F[_]](implicit own: Own[F]) = ???
  }

//  val combined = new CombinedWrapper[String, Int](new SimpleWrapper[String], new SimpleWrapper[Int])
  val strWrapper = new SimpleWrapper[String]
  val intWrapper = new SimpleWrapper[Int]
  val combined = new CombinedWrapper[String, Int, strWrapper.Own, intWrapper.Own](strWrapper, intWrapper)

  type Id[A] = A

  implicit val intOwn: SimpleOwn[Id, Int] = new SimpleOwn[Id, Int] {}
  implicit val stringOwn: SimpleOwn[Id, String] = new SimpleOwn[Id, String] {}

  implicit def composeOwnIds[A, B, ThingA <: OwnThing[Id, A], ThingB <: OwnThing[Id, B]](implicit aOwn: ThingA, bOwn: ThingB): SomeOwnThing[Id, A, B, ThingA, ThingB] = new SomeOwnThing[Id, A, B, ThingA, ThingB] {
    override def underlyingA: ThingA = aOwn
    override def underlyingB: ThingB = bOwn
  }

  combined.ask[Id] // compiles

  new SimpleWrapper[String].ask  // compiles

Использование Aux type

  trait Wrapper[T] {
    type Own[F[_]] <: OwnThing[F, T]
    def ask[F[_]](implicit own: Own[F])
  }

  object Wrapper {
    type Aux[T, Own0[F[_]] <: OwnThing[F, T]] = Wrapper[T] { type Own[F[_]] = Own0[F] }
  }

  class CombinedWrapper[A, B, OwnA[F[_]] <: OwnThing[F, A], OwnB[F[_]] <: OwnThing[F, B]](
    val wrapperA: Wrapper.Aux[A, OwnA], val wrapperB: Wrapper.Aux[B, OwnB]
  ) extends Wrapper[(A, B)] {
    override type Own[F[_]] = SomeOwnThing[F, A, B, OwnA[F], OwnB[F]]
    override def ask[F[_]](implicit own: Own[F]) = ???
  }
...