Witness that an abstract type implements a typeclass

人走茶凉 提交于 2020-12-15 05:37:16

问题


I believe my understanding on this is correct but I'd like to check. When creating typeclasses, it feels neater to have them take a single type parameter, like TypeClass[A]. If the typeclass needs to be parameterized in other ways, abstract types can be used, and there is a comparison of the two approaches here: Abstract types versus type parameters

So far as I have been able to figure out, one thing which is not mentioned in the link is that if using a type parameter, you can witness that the parameter implements a (different) typeclass, likeso:

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

If I use an abstract type, I cannot be sure that it implements IsValidForTC:

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

If so then this makes sense, but this difference isn't mentioned in the link above so I'd like to check.

Thanks!


回答1:


It's your choice whether to put implicit constraints on class level or method level. This makes impact on when the implicits are resolved.

In a type-parameter type class with implicit parameter you don't constrain the type of type class (applied to type parameters), i.e. type TCWithTypeParam[A, B] can be used even if there is no implicit IsValidForTC[B] in a scope. What you do constrain is the constructor of type class. You can emulate this behavior for type-member type class in the following way. Make the constructor private and define apply method (or instance as it's called sometimes) in companion object with desired implicit constraint

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 }
}



回答2:


You can add the witness, but it needs to be inside the class scope so it has access to B:

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

But in practice this is often less convenient than the type parameter, because it has to be implemented explicitly, something like

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

while a constructor parameter just gets the implicit value from outer scope.

Note: this is a partial duplicate of my answer to your follow-up question, but left here in case someone stumbles on this question first.



来源:https://stackoverflow.com/questions/64399785/witness-that-an-abstract-type-implements-a-typeclass

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!