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]
}