Chapter 7

  1. Why is the property of associativity essential for the monoid to be useful in a distributed setup?

In a distributed setup, we're usually talking about folding and reusing datasets with parts of the data being processed by different computers. Monoidal operations are applied on remote machines. Regardless of the order in which they were sent from the master machine, network delays, different load patterns, and hardware settings will influence the order in which they will be returned. It is important to be able to apply an operation on the intermediate results already at hand without waiting for the first operations to complete.

  1. Implement a monoid for Boolean under OR.

The implementation is as follows:

implicit val booleanOr: Monoid[Boolean] = new Monoid[Boolean] {
override def identity: Boolean = false
override def op(l: Boolean, r: Boolean): Boolean = l || r
}

The property is as follows::

property("boolean under or") = {
import Assessment.booleanOr
monoidProp[Boolean]
}
  1. Implement a monoid for Boolean under AND.

The implementation is as follows:

implicit val booleanAnd: Monoid[Boolean] = new Monoid[Boolean] {
override def identity: Boolean = true
override def op(l: Boolean, r: Boolean): Boolean = l && r
}

The property is as follows:

property("boolean under and") = {
import Assessment.booleanAnd
monoidProp[Boolean]
}
  1. Given Monoid[A], implement Monoid[Option[A]].

The implementation is as follows:

implicit def option[A : Monoid]: Monoid[Option[A]] = new Monoid[Option[A]] {
override def identity: Option[A] = None
override def op(l: Option[A], r: Option[A]): Option[A] = (l, r) match {
case (Some(la), Some(lb)) => Option(implicitly[Monoid[A]].op(la, lb))
case _ => l orElse r
}
}

The property is as follows:

property("Option[Int] under addition") = {
import Monoid.intAddition
import Assessment.option
monoidProp[Option[Int]]
}

property("Option[String] under concatenation") = {
import Monoid.stringConcatenation
import Assessment.option
monoidProp[Option[String]]
}
  1. Given Monoid[R], implement Monoid[Either[L, R]].

The implementation is as follows:

def either[L, R : Monoid]: Monoid[Either[L, R]] = new Monoid[Either[L, R]] {
private val ma = implicitly[Monoid[R]]
override def identity: Either[L, R] = Right(ma.identity)
override def op(l: Either[L, R], r: Either[L, R]): Either[L, R] = (l, r) match {
case (l @ Left(_), _) => l
case (_, l @ Left(_)) => l
case (Right(la), Right(lb)) => Right(ma.op(la, lb))
}
}

The property is as follows:

property("Either[Int] under multiplication") = {
import Monoid.intMultiplication
implicit val monoid: Monoid[Either[Unit, Int]] = Assessment.either[Unit, Int]
monoidProp[Either[Unit, Int]]
}

property("Either[Boolean] under OR") = {
import Assessment.booleanOr
implicit val monoid: Monoid[Either[String, Boolean]] = Assessment.either[String, Boolean]
monoidProp[Either[String, Boolean]]
}
  1. Generalize two previous implementations for any effect parameterized by A or describe why it is not possible.

Unfortunately, it is not possible to implement such a monoid in general because the implementation would require two aspects:

  • An identity element for the new monoid
  • A possibility to check whether an effect is empty and retrieve an element if it is not

It is possible to pass an identity element as an argument to the constructor, but then there is no way to work with existing effects as required by the second point.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.162.37