Sehen Sie, dass ein abstrakter Typ eine Typklasse implementiert

Oct 17 2020

Ich glaube, mein Verständnis dafür ist richtig, aber ich würde es gerne überprüfen. Beim Erstellen von Typklassen fühlt es sich besser an, wenn sie einen einzelnen Typparameter verwenden, wie z TypeClass[A]. Wenn die Typklasse auf andere Weise parametrisiert werden muss, können abstrakte Typen verwendet werden, und es gibt hier einen Vergleich der beiden Ansätze: Abstrakte Typen mit Typparametern

Soweit ich herausfinden konnte, wird im Link nicht erwähnt, dass Sie bei Verwendung eines Typparameters feststellen können, dass der Parameter eine (andere) Typklasse implementiert, wie z.

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

Wenn ich einen abstrakten Typ verwende, kann ich nicht sicher sein, ob er Folgendes implementiert IsValidForTC:

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

Wenn ja, dann ist dies sinnvoll, aber dieser Unterschied wird im obigen Link nicht erwähnt, daher möchte ich dies überprüfen.

Vielen Dank!

Antworten

2 DmytroMitin Oct 17 2020 at 11:04

Sie haben die Wahl, ob Sie implizite Einschränkungen auf Klassen- oder Methodenebene festlegen möchten. Dies wirkt sich darauf aus, wann die Implikationen gelöst werden.

In einer Typparameter-Typklasse mit implizitem Parameter beschränken Sie den Typ der Typklasse (angewendet auf Typparameter) nicht, dh Typ TCWithTypeParam[A, B]kann verwendet werden, auch wenn IsValidForTC[B]in einem Bereich kein impliziter Typ vorhanden ist . Was Sie einschränken, ist der Konstruktor der Typklasse. Sie können dieses Verhalten für die Typklasse type-member auf folgende Weise emulieren. Machen Sie den Konstruktor privat und definieren Sie die applyMethode (oder instancewie sie manchmal genannt wird) im Begleitobjekt mit der gewünschten impliziten Einschränkung

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 }
}
1 AlexeyRomanov Oct 20 2020 at 10:58

Sie können den Zeugen hinzufügen, er muss sich jedoch im Klassenbereich befinden, damit er Zugriff auf Folgendes hat B:

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

In der Praxis ist dies jedoch oft weniger bequem als der Typparameter, da er explizit implementiert werden muss, so etwas wie

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

Während ein Konstruktorparameter nur den impliziten Wert aus dem äußeren Bereich erhält.

Hinweis: Dies ist eine teilweise Kopie meiner Antwort auf Ihre Folgefrage , die jedoch hier verbleibt, falls jemand zuerst über diese Frage stolpert.