Scala 3: se débarrasser de l'implicite. Classes de types







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 à jour 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