如果绑定是抽象类型成员,则具有上限类型的高级类型构造函数不起作用
Higher kinded type constructor with upper type bounds doesn't work if bound is abstract type member
我想定义一个由上限 R
和更高种类的类型构造函数 F[_]
参数化的特征,该构造函数仅接受 R
的子类型参数。我希望这个特征实现一个多态 apply
,它可以将任何 F[A]
转换为 Unit
,前提是 A <: R
.
这段代码工作得很好:
import scala.language.higherKinds
// this is the trait with polymorphic `apply`
trait CoCone[R, F[_ <: R]] {
def apply[A <: R](x: F[A]): Unit
}
// Example:
sealed trait Domain
class Dom1 extends Domain
class Fnctr[X <: Domain]
val c = new CoCone[Domain, Fnctr] {
def apply[D <: Domain](x: Fnctr[D]): Unit = ()
}
(见下面关于命名的备注)
现在,如果我通过将 R
声明为某个模块的类型成员来对其进行抽象,并在该模块中定义 Fnctr[A <: R]
,如下所示:
import scala.language.higherKinds
trait CoCone[R, F[_ <: R]] {
def apply[A <: R](x: F[A]): Unit
}
trait ModuleIntf {
type AbstractDomain
class Fnctr[X <: AbstractDomain]
}
// No mention of an actual concrete `Domain` up to
// this point. Now let's try to implement a concrete
// implementation of `ModuleIntf`:
sealed trait Domain
class Dom1 extends Domain
object ModuleImpl extends ModuleIntf {
type AbstractDomain = Domain
val c = new CoCone[Domain, Fnctr] { // error [1], error [2]
def apply[D <: Domain](x: Fnctr[D]): Unit = ()
}
}
一切都崩溃了,我收到两条我不知道如何解释的错误消息:
[1] error: kinds of the type arguments (Domain,Main.$anon.ModuleImpl.Fnctr) do not
conform to the expected kinds of the type parameters (type R,type F) in trait CoCone.
Main.$anon.ModuleImpl.Fnctr's type parameters do not match type F's expected parameters:
type X's bounds <: ModuleIntf.this.AbstractDomain are stricter than type _'s declared bounds <: R
val c = new CoCone[Domain, Fnctr] {
^
[2] error: kinds of the type arguments (Domain,Main.$anon.ModuleImpl.Fnctr) do not
conform to the expected kinds of the type parameters (type R,type F) in trait CoCone.
Main.$anon.ModuleImpl.Fnctr's type parameters do not match type F's expected parameters:
type X's bounds <: ModuleIntf.this.AbstractDomain are stricter than type _'s declared bounds <: R
val c = new CoCone[Domain, Fnctr] {
^
我希望编译器能够识别 ModuleImpl
和 CoCone[Domain, Fnctr]
中的所有三个 Domain = AbstractDomain = R
都是相同的类型。
我是不是遗漏了一些明显的东西,还是 scalac
2.12.4 的限制?如果这是一个限制,有人曾经在任何地方报告过吗?
编辑 发现了类似的东西:issue #10186。是"the same"吗?是不是"the same"?如果它是一个错误,我应该将它作为另一个测试用例提出吗?如果有人可以确认这不完全是我的错,and/or它确实与链接的问题密切相关,那将是一个可以接受的问题解决方案。
Edit2:正如@Evgeny 所指出的,它不能完全是问题 10186,因为它在不同的编译器阶段失败(refchecks
而不是 typer
).
关于名称的说明:我在这里将特征称为CoCone
,类比通常定义的~>
,可以将其视为自然转换,有点。在某种程度上,CoCone[Dom, Fctr]
类似于 Fctr ~> Const_Unit
,但 F
的域仅限于 Dom
的子类型。实际上,CoCone[R, F]
是一个形状为 F
的东西,它可以通过网络发送 R
的某些子类,但这并不重要,所以我已经抽象了名称。这个东西是比较普通的数学构造,没有太做作,要是能编出来就好了。
使用抽象类型成员的工作方法(尝试使用 scalac 2.12.4):
import scala.language.higherKinds
trait CoCone[R, F[_ <: R]] {
def apply[A <: R](x: F[A]): Unit
}
trait ModuleIntf {
type AbstractDomain
type X = ({type XX <: AbstractDomain; type XXX = XX with AbstractDomain})
class Fnctr[X]
}
sealed trait Domain
case class Dom1() extends Domain
object ModuleImpl extends ModuleIntf {
type AbstractDomain = Domain
val f = new Fnctr[Dom1]()
val c = new CoCone[Domain, Fnctr] {
def apply[X](x: Fnctr[X]): Unit = ()
}
c(f)
}
想法取自 issue #4745 的评论。如果我没有遗漏任何东西,这应该等同于原始 non-compilable 方法。
当提到#10186 fails on typer
, but anyway, in #10186补丁时,我发现当前问题在不同的编译器阶段(refchecks
)编译失败,我尝试了它并修复了#10186本身,但仍然报告当前错误。
我会说它应该编译,但我没有发现任何与当前问题类似的问题,所以,假设它还没有报告编译器错误。
在@Andrey 评论后更新。
是的,太专注于获得可编译的版本并且失去了特征的上限。对不起。
在深入了解编译器内部后更新
我调试了一点验证更高种类的类型(scala.reflect.internals.Kinds
大约 checkKindBoundsHK
),看起来在检查 Fnctr
边界时,绑定类型树中没有信息AbstractDomain
是 Domain
的别名。如果我在 object
中将 CoCone 第一个类型更改为 AbstractDomain
,而不是在树中我看到它是 Domain
,但不是 Fnctr
边界。
顺便说一句,fix for #10186 尝试解决类似的问题,评估绑定参数 asSeenFrom
,据我所知试图获得具体类型,但只要在我们的案例中没有进入树中的具体 class,返回 AbstractDomain
..
我想定义一个由上限 R
和更高种类的类型构造函数 F[_]
参数化的特征,该构造函数仅接受 R
的子类型参数。我希望这个特征实现一个多态 apply
,它可以将任何 F[A]
转换为 Unit
,前提是 A <: R
.
这段代码工作得很好:
import scala.language.higherKinds
// this is the trait with polymorphic `apply`
trait CoCone[R, F[_ <: R]] {
def apply[A <: R](x: F[A]): Unit
}
// Example:
sealed trait Domain
class Dom1 extends Domain
class Fnctr[X <: Domain]
val c = new CoCone[Domain, Fnctr] {
def apply[D <: Domain](x: Fnctr[D]): Unit = ()
}
(见下面关于命名的备注)
现在,如果我通过将 R
声明为某个模块的类型成员来对其进行抽象,并在该模块中定义 Fnctr[A <: R]
,如下所示:
import scala.language.higherKinds
trait CoCone[R, F[_ <: R]] {
def apply[A <: R](x: F[A]): Unit
}
trait ModuleIntf {
type AbstractDomain
class Fnctr[X <: AbstractDomain]
}
// No mention of an actual concrete `Domain` up to
// this point. Now let's try to implement a concrete
// implementation of `ModuleIntf`:
sealed trait Domain
class Dom1 extends Domain
object ModuleImpl extends ModuleIntf {
type AbstractDomain = Domain
val c = new CoCone[Domain, Fnctr] { // error [1], error [2]
def apply[D <: Domain](x: Fnctr[D]): Unit = ()
}
}
一切都崩溃了,我收到两条我不知道如何解释的错误消息:
[1] error: kinds of the type arguments (Domain,Main.$anon.ModuleImpl.Fnctr) do not
conform to the expected kinds of the type parameters (type R,type F) in trait CoCone.
Main.$anon.ModuleImpl.Fnctr's type parameters do not match type F's expected parameters:
type X's bounds <: ModuleIntf.this.AbstractDomain are stricter than type _'s declared bounds <: R
val c = new CoCone[Domain, Fnctr] {
^
[2] error: kinds of the type arguments (Domain,Main.$anon.ModuleImpl.Fnctr) do not
conform to the expected kinds of the type parameters (type R,type F) in trait CoCone.
Main.$anon.ModuleImpl.Fnctr's type parameters do not match type F's expected parameters:
type X's bounds <: ModuleIntf.this.AbstractDomain are stricter than type _'s declared bounds <: R
val c = new CoCone[Domain, Fnctr] {
^
我希望编译器能够识别 ModuleImpl
和 CoCone[Domain, Fnctr]
中的所有三个 Domain = AbstractDomain = R
都是相同的类型。
我是不是遗漏了一些明显的东西,还是 scalac
2.12.4 的限制?如果这是一个限制,有人曾经在任何地方报告过吗?
编辑 发现了类似的东西:issue #10186。是"the same"吗?是不是"the same"?如果它是一个错误,我应该将它作为另一个测试用例提出吗?如果有人可以确认这不完全是我的错,and/or它确实与链接的问题密切相关,那将是一个可以接受的问题解决方案。
Edit2:正如@Evgeny 所指出的,它不能完全是问题 10186,因为它在不同的编译器阶段失败(refchecks
而不是 typer
).
关于名称的说明:我在这里将特征称为CoCone
,类比通常定义的~>
,可以将其视为自然转换,有点。在某种程度上,CoCone[Dom, Fctr]
类似于 Fctr ~> Const_Unit
,但 F
的域仅限于 Dom
的子类型。实际上,CoCone[R, F]
是一个形状为 F
的东西,它可以通过网络发送 R
的某些子类,但这并不重要,所以我已经抽象了名称。这个东西是比较普通的数学构造,没有太做作,要是能编出来就好了。
使用抽象类型成员的工作方法(尝试使用 scalac 2.12.4):
import scala.language.higherKinds
trait CoCone[R, F[_ <: R]] {
def apply[A <: R](x: F[A]): Unit
}
trait ModuleIntf {
type AbstractDomain
type X = ({type XX <: AbstractDomain; type XXX = XX with AbstractDomain})
class Fnctr[X]
}
sealed trait Domain
case class Dom1() extends Domain
object ModuleImpl extends ModuleIntf {
type AbstractDomain = Domain
val f = new Fnctr[Dom1]()
val c = new CoCone[Domain, Fnctr] {
def apply[X](x: Fnctr[X]): Unit = ()
}
c(f)
}
想法取自 issue #4745 的评论。如果我没有遗漏任何东西,这应该等同于原始 non-compilable 方法。
当提到#10186 fails on typer
, but anyway, in #10186补丁时,我发现当前问题在不同的编译器阶段(refchecks
)编译失败,我尝试了它并修复了#10186本身,但仍然报告当前错误。
我会说它应该编译,但我没有发现任何与当前问题类似的问题,所以,假设它还没有报告编译器错误。
在@Andrey 评论后更新。
是的,太专注于获得可编译的版本并且失去了特征的上限。对不起。
在深入了解编译器内部后更新
我调试了一点验证更高种类的类型(scala.reflect.internals.Kinds
大约 checkKindBoundsHK
),看起来在检查 Fnctr
边界时,绑定类型树中没有信息AbstractDomain
是 Domain
的别名。如果我在 object
中将 CoCone 第一个类型更改为 AbstractDomain
,而不是在树中我看到它是 Domain
,但不是 Fnctr
边界。
顺便说一句,fix for #10186 尝试解决类似的问题,评估绑定参数 asSeenFrom
,据我所知试图获得具体类型,但只要在我们的案例中没有进入树中的具体 class,返回 AbstractDomain
..