
Mon article précédent portait sur les conversions implicites et les méthodes d'extension. Dans cet article, nous discuterons de la nouvelle façon de déclarer des classes de types dans Scala 3.
Ayant appris à ajouter des méthodes externes à des classes arbitraires, nous voulons aller encore plus loin, à savoir comment convertir des classes arbitraires en interfaces "externes", c'est-à-dire sans en hériter directement. Cette tâche est résolue par les classes de types.
Mais d'abord, voyons ce qu'est une classe de types. Comme le concept lui-même, le terme « classe de type» est originaire de Haskell. Le mot «classe» n'est pas utilisé ici dans le sens étroit qui est accepté dans la POO, mais dans un sens plus large - comme une désignation d'un ensemble d'entités qui ont quelque chose en commun. (Je comprends que la plupart des gens qui liront cet article ont une expérience en POO, et pour eux le terme «classe de type» sonne quelque chose comme «huile d'huiles», bien qu'il signifie «catégorie d'huiles». Pour éviter toute confusion avec les classes OOP conventionnelles , au lieu de "type class", j'utiliserai simplement la translittération "typeclass" - environ transl.)
La syntaxe des exemples est à jourScala 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
.