强制依赖返回类型必须实现typeclass [英] Enforcing that dependent return type must implement typeclass
问题描述
我正在尝试执行一个规则,即类型类的(依赖)返回类型本身必须实现一个类型类.因此,当用户实现下面的IsVec
类型类时,他们还必须确保getElem
方法的返回值实现另一个类型类(IsVecElem
).我试图使这项工作看起来像这样:
// A typeclass for an vector element
abstract class IsVecElem[A, T: Numeric] {
def dataOnly(self: A): T
}
// A typeclass for a vector
abstract class IsVec[A, T: Numeric] {
// I would like this OutElem output type to implement the IsVecElem typeclass
protected type OutElem
def getElem(self: A, i: Int)(implicit tcO: IsVecElem[OutElem, T]): OutElem
}
// give this typeclass method syntax
implicit class IsVecOps[A, T: Numeric](value: A) {
def getElem(i: Int)(implicit tcA: IsVec[A, T], tcO: IsVecElem[tcA.OutElem, T]) = tcA.getElem(value, i)
}
问题与IsVecOps中的getElem一起出现-引发了编译错误:
type OutElem in class IsVec cannot be accessed as a member of IsVec[A, T] from class IsVecOps. Access to protected type OutElem not permitted because enclosing class IsVecOps is not a subclass of class IsVec
具有IsVecOps
扩展IsVec
并不是一个立即解决方案,并且感觉不应该,所以我想知道代码中其他地方的方法是否有错误.
非常感谢任何帮助.
IsVecOps
不应扩展IsVec
.隐式类(仅旨在引入扩展方法)扩展类型类将非常奇怪.
如果暂时删除访问修饰符(protected
),您将看到错误消息更改为
illegal dependent method type: parameter may only be referenced in a subsequent parameter section
def getElem...
尝试添加类型参数(OE
)并指定类型细化(IsVec[A, T] { ... }
)
implicit class IsVecOps[A, T: Numeric](value: A) {
def getElem[OE](i: Int)(implicit tcA: IsVec[A, T] { type OutElem = OE }, tcO: IsVecElem[OE, T]): OE = tcA.getElem(value, i)
}
如果您介绍Aux
-type
object IsVec {
type Aux[A, T, OE] = IsVec[A, T] { type OutElem = OE }
}
然后您可以更紧凑地重写类型细化
implicit class IsVecOps[A, T: Numeric](value: A) {
def getElem[OutElem](i: Int)(implicit tcA: IsVec.Aux[A, T, OutElem], tcO: IsVecElem[OutElem, T]): OutElem = tcA.getElem(value, i)
}
在 Dotty 中,您将可以使用特征参数,扩展方法,多个隐式参数列表,同一参数列表中的参数类型相互依赖:
trait IsVecElem[A, T: Numeric] {
def dataOnly(self: A): T
}
trait IsVec[A, T: Numeric] {
protected type OutElem
def (self: A) getElem(i: Int)(using IsVecElem[OutElem, T]): OutElem
}
或
trait IsVecElem[A, T: Numeric] {
def dataOnly(self: A): T
}
trait IsVec[A, T: Numeric] {
/*protected*/ type OutElem
def getElem(self: A, i: Int)(using IsVecElem[OutElem, T]): OutElem
}
extension [A, T: Numeric](value: A) {
def getElem(i: Int)(using tcA: IsVec[A, T], tcO: isVecElem[tcA.OutElem, T]) = tcA.getElem(value, i)
}
(在0.28.0-bin-20200908-ce48f5a-NIGHTLY中测试)
I am trying to enforce a rule that the (dependent) return type of a typeclass, must itself implement a typeclass. So when the user implements the IsVec
typeclass below, they must also ensure that the return value of the getElem
method implements another typeclass (IsVecElem
). My attempts to make this work look something like this:
// A typeclass for an vector element
abstract class IsVecElem[A, T: Numeric] {
def dataOnly(self: A): T
}
// A typeclass for a vector
abstract class IsVec[A, T: Numeric] {
// I would like this OutElem output type to implement the IsVecElem typeclass
protected type OutElem
def getElem(self: A, i: Int)(implicit tcO: IsVecElem[OutElem, T]): OutElem
}
// give this typeclass method syntax
implicit class IsVecOps[A, T: Numeric](value: A) {
def getElem(i: Int)(implicit tcA: IsVec[A, T], tcO: IsVecElem[tcA.OutElem, T]) = tcA.getElem(value, i)
}
The problem comes with getElem in IsVecOps - this raises a compile error:
type OutElem in class IsVec cannot be accessed as a member of IsVec[A, T] from class IsVecOps. Access to protected type OutElem not permitted because enclosing class IsVecOps is not a subclass of class IsVec
Having IsVecOps
extend IsVec
isn't an immediate solution and doesn't feel like it should be, so I'm wondering if there's an error in approach elsewhere in the code.
Any help much appreciated.
IsVecOps
shouldn't extend IsVec
. Implicit class (with the only purpose to introduce an extension method) extending a type class would be very strange.
If for a moment you remove access modifier (protected
) you'll see that the error message changes to
illegal dependent method type: parameter may only be referenced in a subsequent parameter section
def getElem...
Try to add a type parameter (OE
) and specify type refinement (IsVec[A, T] { ... }
)
implicit class IsVecOps[A, T: Numeric](value: A) {
def getElem[OE](i: Int)(implicit tcA: IsVec[A, T] { type OutElem = OE }, tcO: IsVecElem[OE, T]): OE = tcA.getElem(value, i)
}
If you introduce Aux
-type
object IsVec {
type Aux[A, T, OE] = IsVec[A, T] { type OutElem = OE }
}
then you can rewrite type refinement more compactly
implicit class IsVecOps[A, T: Numeric](value: A) {
def getElem[OutElem](i: Int)(implicit tcA: IsVec.Aux[A, T, OutElem], tcO: IsVecElem[OutElem, T]): OutElem = tcA.getElem(value, i)
}
How can I have a method parameter with type dependent on an implicit parameter?
When are dependent types needed in Shapeless?
Why is the Aux technique required for type-level computations?
Understanding the Aux pattern in Scala Type System
In Dotty you'll be able to use trait parameters, extension methods, multiple implicit parameter lists, types of parameters in the same parameter list dependent on each other:
trait IsVecElem[A, T: Numeric] {
def dataOnly(self: A): T
}
trait IsVec[A, T: Numeric] {
protected type OutElem
def (self: A) getElem(i: Int)(using IsVecElem[OutElem, T]): OutElem
}
or
trait IsVecElem[A, T: Numeric] {
def dataOnly(self: A): T
}
trait IsVec[A, T: Numeric] {
/*protected*/ type OutElem
def getElem(self: A, i: Int)(using IsVecElem[OutElem, T]): OutElem
}
extension [A, T: Numeric](value: A) {
def getElem(i: Int)(using tcA: IsVec[A, T], tcO: isVecElem[tcA.OutElem, T]) = tcA.getElem(value, i)
}
(tested in 0.28.0-bin-20200908-ce48f5a-NIGHTLY)
这篇关于强制依赖返回类型必须实现typeclass的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!