import arrow.Proof import arrow.TypeProof interface Semigroup { fun A.combine(other: A): A interface Syntax { val value: A fun combine(other: A): A } } interface Monoid : Semigroup { fun empty(): A } object StringMonoid : Monoid { override fun String.combine(other: String): String = this + other override fun empty(): String = "" } inline class StringSyntax(override val value: String): Semigroup.Syntax { override fun combine(other: String): String = value + other } @Proof(TypeProof.Extension) fun String.Companion.monoid(): Monoid = StringMonoid @Proof(TypeProof.Extension) fun String.semigroupSyntax(): Semigroup.Syntax = StringSyntax(this)