TLDR; I’ve implemented, on scastie, a pedagogical math function fast-exponent, to help me understand typeclasses. I have completely avoided implicits. QUESITON: how would I refactor this code to use implicits? Or better: should I use implicits?

I’m trying to understand some aspects of typeclasses. There is an object model to understand which I think is easy to neglect once you understand. Rather than all the methods being in one class, we have methods coming from several different classes.

There are two objects in play. One is the sort of model object which contains code (variables, functions, methods) which characterize a class of objects, and separate from that, there’s the object being manipulated.

For example, there is the pair of integers, 3, and 7, which we’d like to add, and separate from that there is an object which represents the monoid of integers inasmuch as it contains/encapsulates the identity-element and plus operation of the monoid.

I’m trying to understand how this whole thing works.

I have implemented a scastie solution monoid fast exponent to the following pedagogical problem.

I think the question of implicit variable obscures the idea. So I’ve written the scastie example avoiding implicit variables altogether.

HERE IS the mathematics problem I’d like to solve for pedagogical reasons.

The code works but I don’t understand how to refactor the code to use implicits.

In any monoid (in any mathematical monoid) I can compute an element raised to an integer power in log(n) operations with the following `power`

function. For example a `String`

repeated `n`

times or a `Double`

raised to the `n`

power. The `power`

function needs to know the `identity`

of the monoid and also the operation, but doesn’t care if that operation is string concatenation, or addition or multiplication or whatever.

```
def power[T](m:T, n:Int, monoid:Monoid[T]):T = {
if (n == 0)
monoid.identity
else if (n == 1)
m
else if (n % 2 == 0) {
val m2 = power(m, n / 2, monoid)
monoid.op(m2, m2)
}
else
monoid.op(m, power(m, n - 1, monoid))
}
trait Monoid[T] {
def op(a:T,b:T):T
var identity:T
}
```

I want to make this work for some exotic monoids:

For example,

- The monoid of matrices containing
`Double`

entries. - The monoid of matrices containing
`Integer`

entries, but where integer addition and multiplication is modulo 5. - The monoid of 2x2 matrices with 3x3 matrices as entries, and these 3x3 matrices contain
`Double`

entries. - The monoid of 2x2 matrices with 3x3 matrices as entries, and these 3x3 matrices contain
`Integer`

entries which use modulo 5, 7, and 11 multiplication.