I have a recurrent problem when modelling typeclass hierarchies. So let’s start with a simple example:

```
trait Monoid[T] {
def apply(lhs: T, rhs: T): T
}
trait Semigroup[T] extends Monoid[T] {
def zero: T
}
```

Now, the underlying logic that we want to expose is that monoids can be extended to a semigroup. Or to put it another way, if you have a semigroup, you can derive a monoid. Now, in interesting cases, we end up with branching patterns of inheritance – a latice of typeclasses. And because Semigroup extends Monoid, you end up with multiple, clashing instances, and all the mess that this gives us.

```
trait Monoid[T] { ... }
trait Semigroup[T] given Monoid[T] { ... }
```

This encoding avoids the inheritance. It means we can only make a semigroup when there is a corresponding monoid. But now when we use it, we need:

```
def someFunc[T] given (M: Monoid[T], S: Semigroup[T]) = ???
```

The list of implied instances rapidly explodes. However, given that we have a semigroup, we know there must be a monoid, because semigroup is defined as requiring a monoid. So we can recover this knowledge:

```
trait Monoid[T] { ... }
trait Semigroup[T] given (val monoid: Monoid[T]) { ... }
implied SemigroupsRequireMonoids [T]
given Semigroup[T] for Monoid[T] = the[Semigroup[T]].monoid
```

We can now write:

```
def foo[T] given Semigroup[T] = {
the[Semigroup[T]] // from the given argument
the[Monoid[T]] // via SemigroupsRequireMonoids
}
```

Now, I freely admit that this is not beautiful. The typeclass lattice is being encoded here by a `given val`

on the trait and is being unpacked by an `implied`

instance that extracts it. However, it does avoid the multiple instances problem and the needing to pass everything in explicitly problem.

So I guess my question is if we can make language improvements for scala 3 that get rid of some of this pain. For example, a way of marking a given on a trait as “exporting” that implied value back out again. For example:

```
trait Semigroup[T] given (implied monoid: Monoid[T]) { ... }
```

so here, by marking the given monoid as implied, that makes it available again but without needing to expose a val or write the implicit extractor.