Currently, the Dotty documentation shows this example of implementing semigroups and monoids.
trait SemiGroup[T]: extension (x: T) def combine (y: T): T trait Monoid[T] extends SemiGroup[T]: def unit: T
And shows this example of using it:
def combineAll[T: Monoid](xs: List[T]): T = xs.foldLeft(summon[Monoid[T]].unit)(_.combine(_))
This seems a bit surprising to me - the extension method
combine magically came into scope when there was a
Monoid[T] in scope, but the method
unit still has to be invoked explicitly on the
It would make more sense if one had to do
import summon[Monoid[T]]._ before being able to use
combine that way. But that’s annoying, so it would be even nicer if one could let the compiler know that
SemiGroup were typeclasses and make it so that whenever there’s an instance of
Monoid is in scope, its members are also in scope, maybe with a
@typeclass trait SemiGroup[T]: extension (x: T) def combine (y: T): T @typeclass trait Monoid[T] extends SemiGroup[T]: def unit: T def combineAll[T: Monoid](xs: List[T]): T = xs.foldLeft(unit)(_.combine(_))
Despite perhaps complicating the language more, it would be more uniform - no special treatment for extensions, and of course, one would still be able to use
summon[Monoid[T]].unit if there happened to be another
unit method in scope or if there was some other ambiguity.
I’ve also opened a feature request issue on Github.