强制依赖类型解析用于隐式调用

时间:2019-07-01 12:52:56

标签: scala implicit type-level-computation path-dependent-type

我具有包装器特征:


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 个答案:

答案 0 :(得分:3)

首先解决几个错字

//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.wrapperAstrWrapper并且combined.wrapperBintWrapper,但是类型combined.wrapperA.Own[Id]strWrapper.Own[Id]是不同的,类型{{ 1}}和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