存在性高阶方法参数

时间:2018-02-12 01:39:41

标签: scala existential-type higher-kinded-types

我定义了以下类型:

trait Context

trait Attribute[C <: Context]

trait AttributeDefinition[A[_ <: Context] <: Attribute[C] forSome { type C <: Context }] {

  def read[C <: Context]: A[C]

}

我希望AttributeDefinition返回由上下文参数化的Attribute。每个定义仅适用于Attribute的一种类型。可以想像:

class ConstantValueAttribute[C <: Context] extends Attribute[C]

object ConstantValueAttributeDefinition extends AttributeDefinition[ConstantValueAttribute] {
  override def read[C <: Context]: ConstantValueAttribute[C] = ???
}

这完全编译好,但是我无法制作接受无界AttributeDefinition的方法签名。以及创建AttributeDefinition s的集合。以下所有都失败了:

def def1(attribute: AttributeDefinition): Unit =  ???
def def2(attribute: AttributeDefinition[_]): Unit = ???
def def3(attribute: AttributeDefinition[_ <: Attribute[C] forSome { type C <: Context }]): Unit = ???
def def4(attribute: AttributeDefinition[A[_]] forSome { type A <: Attribute[C]; type C <: Context })

修改

我正在尝试找到一个像上面那样编译的方法声明。我还想弄清楚如何声明AttributeDefinition s的集合。

val val1 = new mutable.ArrayBuffer[AttributeDefinition]

如果这是不可能的,我想知道如何简化上面的特征仍然可以捕获简单的读取方法声明。

3 个答案:

答案 0 :(得分:3)

具有类型成员的提案

基本上,你想要的defN - 声明和Seq - AttributeDeclaration的集合是Attribute的更高的kinded存在类型,用作参数AttributeDeclaration。所以,理想情况下,您希望:

def def1(attrDef: AttributeDeclaration[A] forSome { 
  type A[C <: Context] <: Attribute[C] }): Unit = ???

但是,这个does not work,这是一个unresolved issue since 2015,所以很有可能它会在dotty之前修复。

我没有尝试强制编译器使用更高的kinded存在,以便你可以丢弃不必要的类型参数,我建议你不要首先添加恼人的类型参数。考虑这些定义(用2.12.4编译):

trait Context
trait Attribute[C <: Context]

trait AttributeDefinition {
  type A[C <: Context] <: Attribute[C]
  def read[C <: Context]: A[C]
}
class ConstantValueAttribute[C <: Context] extends Attribute[C]
object ConstantValueAttributeDefinition extends AttributeDefinition {
  type A[C <: Context] = ConstantValueAttribute[C]
  def read[C <: Context]: ConstantValueAttribute[C] = ???
}
def def1(attrDef: AttributeDefinition): Unit = ???
val collDefs: Seq[AttributeDefinition] = List(ConstantValueAttributeDefinition)

这些定义具有以下属性:

  • ContextAttribute保持不变
  • A成为AttributeDefinition类型成员,因此不必被以后的存在主义强行删除
  • read - 签名完全不变,它与原始代码中的字符相同,字符为
  • 最简单,最直观的def1声明无需更改即可立即生效(基本上也是从您的代码1:1复制而来)
  • 使用AttributeDefinition s的集合的声明和定义也同样顺利。

回想一下,如果从类型参数移动到类型成员,您甚至不会丢失任何内容,因为您始终可以按名称引用类型成员(例如,当您想对该类型成员施加额外限制时)。以下最小示例应该演示如何对类型成员施加额外限制(与您的代码模糊相关,使用Context):

trait Foo {
  type Member
}

def restrictiveFoo(x: Foo { type Member <: Context }): Unit = ???

在这里,您可以强制参与者Foo拥有源自Context的类型成员。它同样适用于type Member = Context。我想通过它来证明:如果你引入它们,它不像类型成员永远隐藏在特征中。你可以使用类型参数几乎所有相同的东西。总结一下:

  • 在(较高的kinded)类型成员上添加其他约束很容易
  • 使用较高的kinded存在率删除多余的参数似乎根本不起作用。

因此,我建议使用类型成员。

将方差从A更改为+A

的提案

使其编译的另一个快速解决方法:

trait Context

trait Attribute[C <: Context]

trait AttributeDefinition[+A[X <: Context] <: Attribute[X]] {
  def read[C <: Context]: A[C]
}

class ConstantValueAttribute[C <: Context] extends Attribute[C]

object ConstantValueAttributeDefinition 
extends AttributeDefinition[ConstantValueAttribute] {
  override def read[C <: Context]: ConstantValueAttribute[C] = ???
}

class FooValueAttribute[C <: Context] extends Attribute[C]
object FooValueAttributeDefinition 
extends AttributeDefinition[FooValueAttribute] {
  override def read[C <: Context]: FooValueAttribute[C] = ???
}

def def1(attrDef: AttributeDefinition[Attribute]): Unit = {}
def1(ConstantValueAttributeDefinition)

val listOfDefs: List[AttributeDefinition[Attribute]] = List(
  ConstantValueAttributeDefinition, 
  FooValueAttributeDefinition
)

受到this question答案的启发。奇怪的是,它似乎几乎完全相同的星座。但是,它并没有解决更高的kinded存在问题,相反,A的方差已更改为+A,因此可以使用Attribute作为所有具体的最小上限{ {1}}秒。

答案 1 :(得分:1)

正确的签名是

def `def`[A[_ <: Context] <: Attribute[C] forSome { type C <: Context }](attribute: AttributeDefinition[A]) = ???

您需要为您的函数使用一个类型参数,该参数应该(至少)具有与您的类型相同的约束。

注意:在我看来,这就是为什么你应该避免对你的类型的类型参数设置类型约束的原因,它们应该只放在函数/操作上。

答案 2 :(得分:0)

trait Context

trait Attribute[+Context]

trait AttributeDefinition[Attribute] {  
    def read[Context]: Attribute 
}


class ConstantValueAttribute extends Attribute[Context]

object ConstantValueAttributeDefinition extends AttributeDefinition[ConstantValueAttribute] {
    def read[Context]: ConstantValueAttribute = ???
}

def def1[C](attribute: AttributeDefinition[C]) : Unit = ???

作为简化的暗示。