Monoid exercises 10.9 from The Red Book
Checking order with Monoid
In this exercise you are given an IndexedSeq[Int]
to be checked whether they are ordered using FoldMap
.
Foldmap definition is given, you need to define :
intOrderMonoid
decide what should be the required monoid type parameter- implement
ordered(iseq : IndexedSeq[Int]) : Boolean
function which will use givenfoldMap
and monoid you just defined.
Fiddle Around!
import cats.Monoid
import scala.math.Ordered
def foldMap[A,B](as : IndexedSeq[A])(f : A=>B)(implicit m : Monoid[B]) = {
as.foldLeft(m.empty) { (b : B, a : A) => m.combine(b, f(a)) }
}
type InOrder = ???
implicit val mon = new Monoid[InOrder] {
def empty = ???
def combine( a : InOrder, b : InOrder) = ???
}
def ordered(iseq : IndexedSeq[Int]) = ???
println(ordered(IndexedSeq(1,2,3,4)) == true)
println(ordered(IndexedSeq(1,3,2,4)) == false)
Solution
Original solution from the Red Book seems a bit more contrived, choosing Option[Int,Int,Boolean]
as monoid type parameter.
Here we just use pair of (Int, Boolean)
:)
In this solution, you keep the latest value, but indicate it whether we are still in order with the boolean flag.
When combining, we require all these flag are still in order, and the right part is bigger than the left.
import cats.Monoid
import scala.math.Ordered
type InOrder = (Int, Boolean)
implicit val mon = new Monoid[InOrder] {
def empty = (Int.MinValue, true)
def combine( a : InOrder, b : InOrder) = {
val (aVal, aInOrder) = a
val (bVal, bInOrder) = b
(bVal, (aInOrder && bInOrder && bVal > aVal))
}
}
def foldMap[A,B](as : IndexedSeq[A])(f : A=>B)(implicit m : Monoid[B]) = {
as.foldLeft(m.empty) { (b : B, a : A) => m.combine(b, f(a)) }
}
def ordered(iseq : IndexedSeq[Int]) = foldMap(iseq)(a => (a,true))._2
println(ordered(IndexedSeq(1,2,3,4)) == true)
println(ordered(IndexedSeq(1,3,2,4)) == false)