
Meu artigo anterior foi sobre conversões implícitas e métodos de extensão. Neste artigo, discutiremos a nova maneira de declarar typeclasses no Scala 3.
Tendo aprendido como adicionar métodos externos a classes arbitrárias, queremos ir ainda mais fundo, ou seja, aprender como converter classes arbitrárias em interfaces "externas", isto é, sem herdar diretamente delas. Esta tarefa é resolvida por typeclasses.
Mas primeiro, vamos descobrir o que é uma typeclass. Como o próprio conceito, o termo " classe de tipo" originou-se em Haskell. A palavra "classe" é usada aqui não no sentido restrito que é aceito em OOP, mas em um sentido mais amplo - como uma designação de um conjunto de entidades que têm algo em comum. (Eu entendo que a maioria das pessoas que irão ler este artigo tem um histórico de OOP, e para eles o termo "typeclass" soa como "óleo de óleos", embora signifique "categoria de óleos". Para evitar confusão com classes OOP convencionais , em vez de "classe de tipo", usarei apenas a transliteração "classe de letras" - transl.
A sintaxe dos exemplos está atualizadaScala 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
.