diff --git a/src/main/scala/fpinscalalib/FPinScalaLibrary.scala b/src/main/scala/fpinscalalib/FPinScalaLibrary.scala
index 13127cf..c1b58c9 100644
--- a/src/main/scala/fpinscalalib/FPinScalaLibrary.scala
+++ b/src/main/scala/fpinscalalib/FPinScalaLibrary.scala
@@ -25,7 +25,8 @@ object FPinScalaLibrary extends Library {
FunctionalStateSection,
FunctionalParallelismSection,
PropertyBasedTestingSection,
- ParserCombinatorsSection
+ ParserCombinatorsSection,
+ MonoidsSection
)
override def logoPath = "fp_in_scala"
diff --git a/src/main/scala/fpinscalalib/MonoidsSection.scala b/src/main/scala/fpinscalalib/MonoidsSection.scala
new file mode 100644
index 0000000..bcc8df3
--- /dev/null
+++ b/src/main/scala/fpinscalalib/MonoidsSection.scala
@@ -0,0 +1,117 @@
+package fpinscalalib
+
+import fpinscalalib.customlib.monoids.Monoid
+import org.scalatest.Matchers
+import org.scalatest.FlatSpec
+
+object MonoidsSection extends FlatSpec
+ with Matchers
+ with org.scalaexercises.definitions.Section {
+
+ /**
+ * = Functional programming in Scala =
+ *
+ * The following set of sections represent the exercises contained in the book "Functional Programming in Scala",
+ * written by Paul Chiusano and RĂșnar Bjarnason and published by Manning. This content library is meant to be used
+ * in tandem with the book. We use the same numeration for the exercises for you to follow them.
+ *
+ * For more information about "Functional Programming in Scala" please visit its
+ * official website.
+ *
+ * = What is a monoid? =
+ *
+ * Exercise 10.1
+ *
+ * Give Monoid instances for integer addition and multiplication as well as the Boolean operators
+ *
+ *
+ * Let's implement Monoid instances for integer addition and multiplication as well as the Boolean operators, taking this representation of `Monoid`:
+ *
+ * {{{
+ * trait Monoid[A] {
+ * def op(a1: A, a2: A): A
+ * def zero: A
+ * }
+ * }}}
+ **/
+ def monoidInstancesAssert(
+ res0: Int,
+ res1: Int,
+ res2: Boolean,
+ res3: Boolean
+ ): Unit = {
+
+ val intAddition: Monoid[Int] = new Monoid[Int] {
+ def op(x: Int, y: Int): Int = x + y
+ def zero: Int = res0
+ }
+
+ val intMultipication: Monoid[Int] = new Monoid[Int] {
+ def op(x: Int, y: Int): Int = x * y
+ def zero: Int = res1
+ }
+
+ val booleanOr: Monoid[Boolean] = new Monoid[Boolean] {
+ def op(x: Boolean, y: Boolean): Boolean = x || y
+ def zero: Boolean = res2
+ }
+
+ def booleanAnd: Monoid[Boolean] = new Monoid[Boolean] {
+ def op(x: Boolean, y: Boolean): Boolean = x && y
+ def zero: Boolean = res3
+ }
+
+ intAddition.op(intAddition.zero, 5) shouldBe 5
+ intAddition.op(5, intAddition.zero) shouldBe 5
+
+ intMultipication.op(intMultipication.zero, 5) shouldBe 5
+ intMultipication.op(5, intMultipication.zero) shouldBe 5
+
+ booleanOr.op(booleanOr.zero, true) shouldBe true
+ booleanOr.op(true, booleanOr.zero) shouldBe true
+ booleanOr.op(booleanOr.zero, false) shouldBe false
+ booleanOr.op(false, booleanOr.zero) shouldBe false
+
+ booleanAnd.op(booleanAnd.zero, true) shouldBe true
+ booleanAnd.op(true, booleanAnd.zero) shouldBe true
+ booleanAnd.op(booleanAnd.zero, false) shouldBe false
+ booleanAnd.op(false, booleanAnd.zero) shouldBe false
+ }
+
+ /**
+ * Exercise 10.2
+ *
+ * Let's give a Monoid instance for combining Option values
+ */
+ def optionMonoidAssert(res0: Option[Int], res1: Option[Int]): Unit = {
+ def optionMonoid[A]: Monoid[Option[A]] = new Monoid[Option[A]] {
+ def op(x: Option[A], y: Option[A]): Option[A] = x.orElse(y)
+ def zero: Option[A] = None
+ }
+
+ optionMonoid[Int].op(Option(2), Option(3)) shouldBe res0
+ optionMonoid[Int].op(Option(2), optionMonoid[Int].zero) shouldBe res1
+ }
+
+ /**
+ * Exercise 10.3
+ *
+ * Let's write a monoid for endofunctions (= functions having the same argument and return type)
+ */
+ def endoMonoidAssert(
+ res0: Int,
+ res1: Int,
+ res2: Int,
+ res3: Int
+ ): Unit = {
+ def endoMonoid[A]: Monoid[A => A] = new Monoid[A => A] {
+ def op(f: A => A, g: A => A): A => A = x => f(g(x))
+ def zero: A => A = x => x
+ }
+
+ endoMonoid[Int].op(_ + 1, _ * 2)(10) shouldBe res0
+ endoMonoid[Int].op(_ * 2, _ + 1)(10) shouldBe res1
+ endoMonoid[Int].op(_ + 1, endoMonoid[Int].zero)(10) shouldBe res2
+ endoMonoid[Int].op(endoMonoid[Int].zero, endoMonoid[Int].zero)(10) shouldBe res3
+ }
+}
diff --git a/src/main/scala/fpinscalalib/customlib/monoids/Monoid.scala b/src/main/scala/fpinscalalib/customlib/monoids/Monoid.scala
new file mode 100644
index 0000000..03ceaf2
--- /dev/null
+++ b/src/main/scala/fpinscalalib/customlib/monoids/Monoid.scala
@@ -0,0 +1,6 @@
+package fpinscalalib.customlib.monoids
+
+trait Monoid[A] {
+ def op(a1: A, a2: A): A
+ def zero: A
+}
diff --git a/src/test/scala/fpinscalalib/MonoidsSpec.scala b/src/test/scala/fpinscalalib/MonoidsSpec.scala
new file mode 100644
index 0000000..8044076
--- /dev/null
+++ b/src/test/scala/fpinscalalib/MonoidsSpec.scala
@@ -0,0 +1,12 @@
+package fpinscalalib
+
+import org.scalatest.refspec.RefSpec
+import org.scalatest.prop.Checkers
+
+class MonoidsSpec extends RefSpec with Checkers {
+ def `monoid instances asserts` = {
+ MonoidsSection.monoidInstancesAssert(0, 1, false, true)
+ MonoidsSection.optionMonoidAssert(Option(2), Option(2))
+ MonoidsSection.endoMonoidAssert(21, 22, 11, 10)
+ }
+}