A group adds an invertibility property to the properties of the monoid, which means that for every element, a, from the set, S, on which the group is defined, there is an inverse element so that the result of the operation on both of them is an identity element.
Formalized in the code, it looks like the following:
trait Group[S] extends Monoid[S] {
def inverse(a: S): S
}
The ScalaCheck property for this new law looks similar to the properties we defined for semigroup and monoid:
def invertibility[S : Group : Arbitrary]: Prop =
forAll((a: S) => {
val m = implicitly[Group[S]]
m.op(a, m.inverse(a)) == m.identity && m.op(m.inverse(a), a) == m.identity
})
Like we did previously, we can define an overarching check that aggregates single properties:
def groupProp[S : Group: Arbitrary]: Prop = monoidProp[S] && invertibility[S]
By adding a commutative property...