2016-11-23 3 views
1

Ich versuche, ein wenig anspruchsvolle Beispiel von typeclasses in Scala zu implementieren: konvertieren Wert des Typs T in String als Bibliothek implementiert ein Benutzer kann für jeden Typ T erweitert. Also hier ist das Merkmal alle typeclasses implementieren sollte: die Arbeit gehen zu nennenImportieren implicits aus einer Unterklasse

trait Printable[T] { 
    def asString(value: T): String 
} 

die Funktion, die wir zu tun: mit einer Reihe von typeclasses für einige Standardtypen

object Printer { 
    def print[T](value: T)(implicit p:Printable[T]): String = p.asString(value) 
} 

Object (nur int & lange hier zum Beispiel):

object SimpleFormats extends Formats 

trait Formats { 
    implicit val intFormat = new Printable[Int] { 
    override def asString(value: Int) = value.toString 
    } 
    implicit val longFormat = new Printable[Long] { 
    override def asString(value: Long) = value.toString 
    } 
} 

Stellen Sie sich vor, dass der Benutzer unsere Bibliothek für einen anderen Typ wie Float und Double erweitern möchte. Er erstellt also ein anderes Objekt, indem es das erste untergliedert. Die Idee dabei ist, neue implizite Mitglieder an der Basis Objekt hinzufügen, so kann die Standardsammlung von typeclasses für beliebig viele Benutzer gelieferten Typen erweitert werden:

object ExtendedFormats extends Formats { 
    implicit val floatFormat = new Printable[Float] { 
    override def asString(value: Float) = value.toString 
    } 
    implicit val doubleFormat = new Printable[Double] { 
    override def asString(value: Double) = value.toString 
    } 
} 

Und schließlich die wichtigsten app unserer Bibliothek. Es gibt zwei Beispielfunktionen Operationen auf verschiedene Arten tun, so ist es nicht möglich, einzelne spezifische implizite Printer[T] als liefern:

  • gibt es mehrere Operationen auf mehrere Arten
  • die Printer nicht vorher wissen, welche Arten zugeführt werden kann vom Benutzer.

So ist die Haupt-App sieht wie folgt aus:

object Example { 
    // compiles OK, uses only default typeclasses 
    def simpleExample(implicit formats: Formats) = { 
    import formats._ 
    Printer.print(42) + Printer.print(24L) 
    } 

    // compilation failed, cannot find Printable[Float] 
    // uses user-supplied formats 
    def extendedExample(implicit formats: Formats) = { 
    import formats._ 
    Printer.print(42f) + Printer.print(31337.0) 
    } 

    def main(args: Array[String]): Unit = { 
    implicit val formats = ExtendedFormats 
    println(simpleExample) 
    println(extendedExample) 
    } 
} 

Ich sehe, dass scala Compiler versucht implicits vom Formats zu importieren, die Tatsache zu ignorieren, dass es ExtendedFormats tatsächlich ist.

Fragen:

  • Gibt es eine Möglichkeit implicits von einer Unterklasse zu importieren, wie im Beispiel beschrieben?
  • Gibt es eine bessere Lösung für eine Charge von benutzerdefinierten Typklassen?
+0

Sie können in [Simulacrum] (https://github.com/mpilquist/simulacrum) nach Typklassen suchen. –

Antwort

2

Wenn Sie im Voraus wissen, dass Ihr Code Printable für Float benötigt und für Double dann könnten Sie es direkt erklären:

def extendedExample(implicit floatPrintable: Printable[Float], doublePrintable: Printable[Double]) = { 
    Printer.print(42f) + Printer.print(31337.0) 
} 

oder eine Sammlung von Format -ähnliche Züge erstellen:

trait FormatDouble { 
    implicit val doubleFormat: Printable[Double] 
} 

und geben Sie dann an, welche Typen Sie benötigen:

def extendedExample(implicit formats: Formats with FormatDouble with FormatFloat) = { 
    import formats._ 
    Printer.print(42f) + Printer.print(31337.0) 
} 
Verwandte Themen