Scala 3: Implizites loswerden. Typenklassen







In meinem vorherigen Artikel ging es um implizite Konvertierungen und Erweiterungsmethoden. In diesem Artikel wird die neue Methode zum Deklarieren von Typklassen in Scala 3 erläutert.







Nachdem wir gelernt haben, wie man willkürlichen Klassen externe Methoden hinzufügt, wollen wir noch tiefer gehen, nämlich wie man willkürliche Klassen in "externe" Schnittstellen konvertiert, dh ohne direkt von ihnen zu erben. Diese Aufgabe wird durch Typklassen gelöst.







Aber zuerst wollen wir herausfinden, was eine Typklasse ist. Wie das Konzept selbst stammt der Begriff " Typklasse" aus Haskell. Das Wort "Klasse" wird hier nicht im engeren Sinne verwendet, der in OOP akzeptiert wird, sondern im weiteren Sinne - als Bezeichnung für eine Reihe von Entitäten, die etwas gemeinsam haben. (Ich verstehe, dass die meisten Leute, die diesen Artikel lesen werden, einen OOP-Hintergrund haben, und für sie klingt der Begriff "Typklasse" so etwas wie "Öl von Ölen", obwohl er "Kategorie von Ölen" bedeutet. Um Verwechslungen mit herkömmlichen OOP-Klassen zu vermeiden , anstelle von "Typklasse" verwende ich nur die Transliteration "Typklasse" - ca. transl.)







Die Syntax der Beispiele ist aktuell Scala 3.0.0-M3



.

, , , . Scala 3:







// Adapted from this Dotty documentation:
// https://dotty.epfl.ch/docs/reference/contextual/type-classes.html

trait Semigroup[T]:
  extension (t: T)
    def combine(other: T): T
    def <+>(other: T): T = t.combine(other)

trait Monoid[T] extends Semigroup[T]:
  def unit: T
      
      





, <+>



. — , , 0 — . , Semigroup



Monoid



.







Semigroup



T



extension- combine



<+>



, combine



. unit



Monoid



, extension-. , unit



T



, , , T



, .







:







given StringMonoid: Monoid[String] with
  def unit: String = ""
  extension (s: String) def combine(other: String): String = s + other

given IntMonoid: Monoid[Int] with
  def unit: Int = 0
  extension (i: Int) def combine(other: Int): Int = i + other
      
      





. , given foo: Bar



— implicit-. Scala3 REPL, , : StringMonoid



IntMonoid



.







- :







"2" <+> ("3" <+> "4")             // "234"
("2" <+> "3") <+> "4"             // "234"
StringMonoid.unit <+> "2"         // "2"
"2" <+> StringMonoid.unit         // "2"

2 <+> (3 <+> 4)                   // 9
(2 <+> 3) <+> 4                   // 9
IntMonoid.unit <+> 2              // 2
2 <+> IntMonoid.unit              // 2
      
      





StringMonoid



IntMonoid



unit



. <+>



extension-, String



Int



. <+>



, .







: given Monoid[String] with ...



. unit



summon[Monoid[String]]



. summon



implicitly



, implicit- . given_Monoid_String



, , .







, , - ( unit



). .







, . , , IntMonoid



Numeric[T]



:







given NumericMonoid[T](using num: Numeric[T]): Monoid[T] with
  def unit: T = num.zero
  extension (t: T) def combine(other: T): T = num.plus(t, other)

2.2 <+> (3.3 <+> 4.4)             // 9.9
(2.2 <+> 3.3) <+> 4.4             // 9.9

BigDecimal(3.14) <+> NumericMonoid.unit
NumericMonoid[BigDecimal].unit  <+> BigDecimal(3.14)
      
      





using



, Scala 2 implicit



. .







. NumericMonoid



— , Monoid[T]



— . T



, . NumericMonoid[BigDecimal]



, NumericMonoid



BigDecimal



. num



NumericMonoid



, using



.







, unit



. -, <+>



. Scala obj1.method(obj2)



.







?



using



.








All Articles