见证一个抽象类型实现一个类型类。

14 浏览
0 Comments

见证一个抽象类型实现一个类型类。

我相信我对此的理解是正确的,但我想确认一下。创建类型类时,让它们只接受一个类型参数(如`TypeClass[A]`)会更整洁。如果类型类需要以其他方式进行参数化,可以使用抽象类型,这里有两种方法的比较:

抽象类型与类型参数

据我所了解,在链接中没有提到的一点是,如果使用类型参数,可以证明该参数实现了一个(不同的)类型类,如下所示:

trait IsValidForTC[A]
abstract class TCWithTypeParam[A, B] (implicit ev: IsValidForTC[B]) {}

如果使用抽象类型,我无法确保它实现了`IsValidForTC`:

abstract class TCWithAbstractType[A] (implicit ev: IsValidForTC[B]) {
    type B
} //找不到:类型B

如果是这样的话,这是有道理的,但上面的链接中没有提到这个差别,所以我想确认一下。

谢谢!

0
0 Comments

问题的原因是在使用抽象类型实现类型类时,编译器无法在类级别确定抽象类型是否实现了类型类的约束。这是因为抽象类型可能有其他的构造函数,这些构造函数不一定强制要求抽象类型实现类型类的约束。因此,需要将类型类的证明放在方法级别,这虽然在功能上是可以的,但需要更多的样板代码。

为了解决这个问题,可以将类型类的构造函数设为私有,并在伴生对象中定义一个带有所需隐式约束的apply方法。通过这种方式,可以在方法级别上进行类型类的约束,并且可以保证抽象类型实现了类型类的约束。

下面是一个使用这种解决方法的示例:

abstract class TCWithAbstractType[A] private {
  type B
}
object TCWithAbstractType {
  def apply[A, _B: IsValidForTC]: TCWithAbstractType[A] { type B = _B } = 
    new TCWithAbstractType[A] { type B = _B }
}

在这个示例中,TCWithAbstractType类的构造函数被设置为私有,并在伴生对象中定义了一个apply方法。这个apply方法接受类型参数A和一个隐式参数_B,其中_B必须满足IsValidForTC的约束。通过这种方式,可以在使用TCWithAbstractType时保证抽象类型B实现了IsValidForTC的约束。

需要注意的是,私有构造函数仍然可以在伴生对象中访问(而隐式实例通常是在伴生对象中定义的),可以将主构造函数设置为private,将所有的辅助构造函数设置为private[this],这样它们在伴生对象中也将无法访问。

总结起来,通过在伴生对象中定义带有所需隐式约束的apply方法,可以在方法级别上实现抽象类型对类型类的约束。这种解决方法可以兼顾类型类的约束和灵活性。

0
0 Comments

问题的出现原因是:在实现一个类型类时,如果使用抽象类型(abstract type)作为类型参数,需要确保抽象类型的证明(witness)可以在类的作用域内访问。然而,这种方法通常不如使用类型参数方便,因为抽象类型的证明必须显式地实现。

解决方法是:将抽象类型和证明(witness)放在类的作用域内,并通过构造函数参数传递隐式值。这样可以从外部作用域获取隐式值,避免在每次实现时显式地指定证明。

以下是示例代码:

abstract class TCWithAbstractType[A] {
    type B
    implicit val ev: IsValidForTC[B]
}
new TCWithAbstractType[A] {
    type B = ...
    implicit val ev: IsValidForTC[B] = ...
}

注意:这个解决方法的部分内容与我在你的后续问题中的答案相似,但仍保留在这里,以防有人先看到这个问题。

0