Mi artículo anterior trataba sobre conversiones implícitas y métodos de extensión. En este artículo, discutiremos la nueva forma de declarar clases de tipos en Scala 3.
Habiendo aprendido cómo agregar métodos externos a clases arbitrarias, queremos profundizar aún más, es decir, aprender a convertir clases arbitrarias en interfaces "externas", es decir, sin heredar directamente de ellas. Esta tarea se resuelve mediante clases de tipos.
Pero primero, averigüemos qué es una clase de tipos. Al igual que el concepto en sí, el término " clase de tipo" se originó en Haskell. La palabra "clase" se utiliza aquí no en el sentido estricto que se acepta en la programación orientada a objetos, sino en un sentido más amplio, como una designación de un conjunto de entidades que tienen algo en común. (Entiendo que la mayoría de las personas que leerán este artículo tienen antecedentes de OOP, y para ellos el término "tipo de clase" suena como "aceite de aceites", aunque significa "categoría de aceites". Para evitar confusiones con las clases de OOP convencionales , en lugar de "type class", solo usaré la transliteración "typeclass" - aprox. transl.)
La sintaxis de los ejemplos está actualizadaScala 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
.