Beginner questions about type classes

perhaps it is too early to generalize, but it seems to me that type classes basically allow you to define methods on classes you don’t own

Here is a simple example of one very useful thing you can do with a type class

trait Semigroup[A] {
  def combine(l: A, r: A): A
}

implicit val intSemigroup = new Semigroup[Int] {
  def combine(l: Int, r: Int): Int = l + r
}

implicit val stringSemigroup = new Semigroup[String] {
  def combine(l: String, r: String): String = l + r
}

intSemigroup.combine(2,3)
stringSemigroup.combine("2","3")

def combine3[A](x: A, y: A, z: A)(implicit sg:Semigroup[A]): A =
  sg.combine(sg.combine(x,y),z)

combine3(2,3,4)
combine3("2","3","4")

def combineAll[A](as: Seq[A])(implicit sg:Semigroup[A]): A =
  as.reduce(sg.combine(_,_))

combineAll(Seq(2,3,4))
combineAll(Seq("2","3","4"))

implicit def listSemigroup[A] = new Semigroup[List[A]] {
  def combine(l: List[A], r: List[A]): List[A] = l ++ r
}

combineAll(Seq(List(2,3), Nil, List(4)))

implicit def optionSemigroup[A] = new Semigroup[Option[A]] {
  def combine(l: Option[A], r: Option[A]): Option[A] = l orElse r
}

combineAll(Seq(Some(2), None, Some(3)))
combineAll(Seq(None, None, Some(3)))