Scala 高级类型的Aux模式

Scala 高级类型的Aux模式,scala,type-level-computation,higher-kinded-types,Scala,Type Level Computation,Higher Kinded Types,编辑:下面是一个更简单的问题公式,使用Foo作为Aux模式的一个示例,该模式确实有效: 问题的旧提法: 为下面这个复杂的例子道歉。我基本上想要复制高级类型的Aux模式 scala: // Foo is a normal Aux pattern calculation trait Foo[A, B] { type Out } object Foo { type Aux[A, B, C] = Foo[A, B] { type Out = C } // Foo turns Int + St

编辑:下面是一个更简单的问题公式,使用
Foo
作为
Aux
模式的一个示例,该模式确实有效:


问题的旧提法:

为下面这个复杂的例子道歉。我基本上想要复制高级类型的
Aux
模式

scala:

// Foo is a normal Aux pattern calculation
trait Foo[A, B] { type Out }

object Foo {
  type Aux[A, B, C] = Foo[A, B] { type Out = C }
  // Foo turns Int + String into Boolean
  implicit val intInstance: Foo.Aux[Int, String, Boolean] = null
}

// Wrapper is supposed to be a type-level computation across
// type-level functions
// It takes two types and binds them with a contract (a nested
// type-level function)
trait Wrapper[A, B] { type Contract[X] }

object Wrapper {
  type Aux[A, B, C[_]] = Wrapper[A, B] { type Contract[X] = C[X] }

  // It has one instance: It binds Int and String to the type-level
  // function Foo.
  implicit val fooWrapper: Wrapper.Aux[Int, String, Foo.Aux[Int, String, ?]] = null

}

object Testing {

  trait TestResult[X]

  // We summon a Contr, which is provided by Wrapper
  // The idea is we get the result of Foo's computation without summoning
  // Foo explicitly. This allows us to easily swap Foo out for another
  // Function if we desire
  implicit def testing[A, B, Contr[_], X](
    implicit wrapper: Wrapper.Aux[A, B, Contr],
    foo: Contr[X]
  ): TestResult[X] = ???


  // Compiles as expected
  implicitly[Wrapper.Aux[Int, String, Foo.Aux[Int, String, ?]]]
  implicitly[Wrapper[Int, String]]
  implicitly[Foo.Aux[Int, String, Boolean]]
  implicitly[Foo[Int, String]]
  val result1: TestResult[Boolean] = testing[Int, String, Foo.Aux[Int, String, ?], Boolean]

  // Does not compile
  val result2: TestResult[Boolean] = testing
  implicitly[TestResult[Boolean]]
}
这就是我希望在最后一行中发生的事情:

  • 我们正在搜索一个
    TestResult[Boolean]
  • 测试
    说我们需要一个
    控件[Boolean]
    用于
    包装器提供的一些
    控件
  • Wrapper
    给出了
    Contr[\u]=Foo.Aux[Int,String,,]的单个实例。
  • 所以编译器正在搜索
    Foo.Aux[Int,String,Boolean]
  • Foo
  • 所以整件事都是经过编译的
这是我的
build.sbt
,以防我遗漏了什么:

scalaVersion := "2.12.6"

scalacOptions := Seq(
  "-language:existentials",
  "-language:higherKinds",
  "-Ypartial-unification",  // EDIT
)

addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.8")

我想出了一个解决方案:

trait Wrapper[A, B] { type Contract[_] }

object Wrapper {
  type Aux[A, B, C[_]] = Wrapper[A, B] { type Contract[_] = C[_] }
  // One instance, linking Int + String to Option
  implicit def instance[A, B](implicit ev1: A =:= Int, ev2: B =:= String): Wrapper.Aux[A, B, Option] = null

}

object Testing {

  def wrapperTest[A, B, X[_]](implicit ev: Wrapper.Aux[A, B, X]): X[Boolean] = ???

  // These compile now!!
  wrapperTest
  wrapperTest: Option[Boolean]

  // Do NOT compile, as expected
  // wrapperTest[Boolean, Char, Option]: Option[Boolean]
  // wrapperTest[Int, String, List]: Option[Boolean]

}

我不知道为什么它能精确地工作,但似乎
A
B
的自由让编译器能够专注于正确解析
X[\u]
,然后,对
A
B
的约束发生在不同的级别,因此我们最终实现了相同的功能。

您提出了一个有趣的解决方法,但最初的问题确实是一个bug:,在Scala 2.13中修复了该问题:。不幸的是,它不能被后传到2.12,因为它改变了类型推断的工作方式,这是编译器中一个微妙的部分,甚至没有被指定。但是您可以使用Scala 2.13.0-M4或2.13.0-M5进行尝试。

还没有仔细研究过它,但是如果您的代码中有
[X,?]
任何地方有疑问,请指出。感谢您指出,这是一个遗漏。然而不幸的是,它并没有解决这个问题!谢谢你的回复
trait Wrapper[A, B] { type Contract[_] }

object Wrapper {
  type Aux[A, B, C[_]] = Wrapper[A, B] { type Contract[_] = C[_] }
  // One instance, linking Int + String to Option
  implicit def instance[A, B](implicit ev1: A =:= Int, ev2: B =:= String): Wrapper.Aux[A, B, Option] = null

}

object Testing {

  def wrapperTest[A, B, X[_]](implicit ev: Wrapper.Aux[A, B, X]): X[Boolean] = ???

  // These compile now!!
  wrapperTest
  wrapperTest: Option[Boolean]

  // Do NOT compile, as expected
  // wrapperTest[Boolean, Char, Option]: Option[Boolean]
  // wrapperTest[Int, String, List]: Option[Boolean]

}