【问题标题】:Witness that an abstract type implements a typeclass见证抽象类型实现了类型类
【发布时间】:2021-01-31 14:28:31
【问题描述】:

我相信我对此的理解是正确的,但我想检查一下。创建类型类时,让它们采用单个类型参数感觉更简洁,例如TypeClass[A]。如果 typeclass 需要通过其他方式参数化,可以使用抽象类型,这里有两种方式的对比: Abstract types versus type parameters

据我所知,链接中没有提到的一件事是,如果使用类型参数,您可以看到该参数实现了一个(不同的)类型类,如下所示:

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

如果我使用抽象类型,我无法确定它是否实现了IsValidForTC

abstract class TCWithAbstractType[A] (implicit ev: IsValidForTC[B]) {
    type B
} //not found: Type B

如果是这样,那么这是有道理的,但是上面的链接中没有提到这种差异,所以我想检查一下。

谢谢!

【问题讨论】:

    标签: scala generics typeclass implicit


    【解决方案1】:

    您可以选择是否在类级别或方法级别设置隐式约束。这会影响何时解决隐式。

    在具有隐式参数的类型参数类型类中,您不限制类型类的类型(应用于类型参数),即类型 TCWithTypeParam[A, B] 可以使用,即使范围内没有隐式 IsValidForTC[B] .您所做的约束是类型类的构造函数。您可以通过以下方式为类型成员类型类模拟此行为。将构造函数设为私有并在具有所需隐式约束的伴随对象中定义 apply 方法(或有时称为 instance

    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 时,编译器无法“知道”B 保证实现IsValidForTC。这似乎是合乎逻辑的,因为TCWithAbstractType 可能有其他构造函数,它们不一定强制执行B 实现IsValidForTC 的约束。这意味着 typeclass 见证必须放在方法级别,这在功能上是可以的,但需要更多的样板。我是否正确理解了情况?如果我不清楚,请告诉我,我会提出一个新问题。
    • @Chrisper "当使用TCWithAbstractType 时,编译器无法“知道”B 保证实现IsValidForTC" 取决于使用方式。使用 type TCWithTypeParam[A, B]/TCWithAbstractType[A] { type B =... } 不受限制,其中 实例化 是受限制的。 TCWithAbstractType 可能有其他构造函数” 当您在伴生对象中创建 apply 方法时,您还将 所有 构造函数设为私有。
    • @Chrisper “必须放在方法级别,这在功能上还可以,但需要更多样板” 类级别与方法级别的隐式之间的区别不是在或多或少的样板文件中,隐式解析的语义在这些情况下是不同的(构造函数/apply 方法调用与方法调用时的解析)。
    • 谢谢 - 我想我理解你,但我会整理一个简单的例子并把它放在一个新的问题中以确保。
    【解决方案2】:

    您可以添加见证,但它需要在类范围内,以便它可以访问B

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

    但实际上这通常不如类型参数方便,因为它必须显式地实现,类似于

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

    虽然构造函数参数只是从外部范围获取隐式值。

    注意:这是我对your follow-up question 的回答的部分副本,但留在这里以防有人先发现这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-02
      • 2018-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-17
      • 1970-01-01
      相关资源
      最近更新 更多