
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 aktuellScala 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
.