Creating a custom Monoid with Scala and Cats
In this article, I will demonstrate how a monoid (not yet a monad!) is created using Scala and Cats. The motivation for this was this old…
Creating a custom Monoid with Scala and Cats

Image completely unrelated, compared to hiking in the alps, monoids are a piece of cake!
In this article, I will demonstrate how a monoid (not yet a monad!) is created using Scala and Cats. The motivation for this was this old Stackoverflow question of mine.
First of all, some definitions:
- A
[Monoid](https://typelevel.org/cats/typeclasses/monoid.html) is aSemigroupwith an additionalemptyvalue - A type can form a
[Semigroup](https://typelevel.org/cats/typeclasses/semigroup.html) if it has an associative binary operation (combine)
What we want to create is something similar to Scala’s Either in a sense that we want to have have a type that can show the result of a computation. Let’s call it Result. Result will differ just a bit from a regular Either in the way that it can be combined. Cats provides syntax for the combine method in the form of the |+| operator.
Here are some example use cases for Result and how it differs from Either when combining multiple instances of it:
val e1: Either[String, Int] = Right(1)
val e2: Either[String, Int] = Right(2)
val e3: Either[String, Int] = Left("request failed")
val combined1 = e1 |+| e2 |+| e3
assert(combined1 == Left("request failed"))
val r1: Result[Int] = Result(1)
val r2: Result[Int] = Result(2)
val r3: Result[Int] = Failed("request failed")
val combined2 = r1 |+| r2 |+| r3
assert(combined2 == Succeeded(NonEmptyList.of(1, 2)))
With our goal set, let’s jump to the implementation of Result!
The Result class
The basic Result definition looks like this:
object Result extends ResultInstances {
def apply[A](values: A*): Result[A] =
NonEmptyList.fromList(values.toList)
.map(nel => Succeeded(nel)).getOrElse(Failed())
}
sealed trait Result[+A] {
def vs: Seq[A] = this match {
case Succeeded(xs) => xs.toList
case _ => Nil
}
}
case class Succeeded[A](values: NonEmptyList[A]) extends Result[A]
case class Failed(reason: String = "") extends Result[Nothing]
As we can see there is already a lot going on. We have created a trait called Result with two classes that extend that type: Succeeded and Failed . Succeeded has a non-empty list of result values, while Failed can contain the failure reason as a String (obviously this could be extended to e.g. a Throwable or a generic type, but for the sake of simplicity, we will use a String for now).
Additionally, I added a small helper method vs to the trait that returns all values stored in that Result instance.
The companion object for Result serves two purposes:
- Offer a convenient apply method, so that we can create
Results like this:
Result(1) // equals Succedded(NonEmptyList.one(1))
Result() // equals Failed("")
- Bring
ResultInstancesinto scope, wheneverResultis used.
Writing the Monoid Type-class for Result
The implementation for ResultInstances is quite straight-forward:
sealed abstract class ResultInstances {
implicit def resultInstance[A]: Monoid[Result[A]] =
new Monoid[Result[A]] {
override def empty: Result[A] = Failed()
override def combine(x: Result[A], y: Result[A]): Result[A] =
Result.apply(x.vs ++ y.vs: _*)
}
}
As we discussed in the first part of this article, the Monoid of Result needs to implement two methods: empty and combine. For the empty value, we need to use Failed, since Failed |+| x (where x is a Result) is equal to just x. combine creates a new Result with combined inner values. Notice that combine(Failed, Failed) returns Failed (in our case, we would loose both failure messages when combining two Failed instances, though).
And that’s it! We succesfully implemented our new Monoid! The code can be found in my github repository.
메타데이터
- post_id
- 5f01bd4f4a14
- slug
- creating-a-custom-monoid-with-scala-and-cats-5f01bd4f4a14
- url
- https://medium.com/@fbaierl1/creating-a-custom-monoid-with-scala-and-cats-5f01bd4f4a14
- canonical_url
- https://medium.com/@fbaierl1/creating-a-custom-monoid-with-scala-and-cats-5f01bd4f4a14
- author_url
- https://medium.com/@fbaierl1
- status
- ok
- fetched_at
- 2026-06-20 20:29:01