Commit 983b9eb2 authored by Haochen Xie's avatar Haochen Xie

add ch10/Monoids.scala

parent 757fd0d8
package name.haochenxie.fpscala.ch10
import scala.collection.mutable.ArrayBuffer
trait Monoid[A] {
def op(a1: A, a2: A): A
def zero: A
}
object Monoids {
val stringMonoid = new Monoid[String] {
override def op(a1: String, a2: String): String = a1 + a2
override val zero: String = ""
}
def listMonoid[A] = new Monoid[List[A]] {
override def op(a1: List[A], a2: List[A]): List[A] = a1 ++ a2
override val zero: List[A] = Nil
}
// Exercise 10.1
val intAddition = new Monoid[Int] {
override def op(a1: Int, a2: Int): Int = a1 + a2
override val zero: Int = 0
}
val intMultiplication = new Monoid[Int] {
override def op(a1: Int, a2: Int): Int = a1 * a2
override val zero: Int = 1
}
val booleanOr = new Monoid[Boolean] {
override def op(a1: Boolean, a2: Boolean): Boolean = a1 || a2
override val zero: Boolean = false
}
val booleanAnd = new Monoid[Boolean] {
override def op(a1: Boolean, a2: Boolean): Boolean = a1 && a2
override val zero: Boolean = true
}
// Exercise 10.2
// I'm not sure about the expected semantics..
def optionMonoid[A] = new Monoid[Option[A]] {
override def op(a1: Option[A], a2: Option[A]): Option[A] = a1.flatMap(_ => a2)
override val zero: Option[A] = Option.empty
}
// Exercise 10.3
def endoMonoid[A] = new Monoid[A => A] {
// hmm, no idea which one should be called first..
override def op(a1: (A) => A, a2: (A) => A): (A) => A = a1 andThen a2
override val zero: (A) => A = Predef.identity
}
// Exercise 10.4
// will do after looking at Chapter 8
// Exercise 10.5
def foldMap[A,B](as: List[A], m: Monoid[B])(f: A => B): B =
as.map(f).foldLeft(m.zero)(m.op)
def concatenate[A](as: List[A], m: Monoid[A]): A =
foldMap(as, m)(Predef.identity)
// Exercise 10.6
// well, for later
// Exercise 10.7
def foldMapV[A,B](v: IndexedSeq[A], m: Monoid[B])(f: A => B): B =
if (v.isEmpty) m.zero
else if (v.length == 1) f(v.head)
else v.splitAt(v.length / 2) match {
case (v1, v2) => m.op(foldMapV(v1, m)(f), foldMapV(v2, m)(f))
}
// Exercise 10.8
// will do after looking at Chapter 7
// Exercise 10.9
def ordered(v: IndexedSeq[Int]): Boolean = {
sealed trait K {
def isOrdered: Boolean
}
case class Disordered() extends K { val isOrdered = false }
case class Identity() extends K { val isOrdered = true }
case class Range(a: Int, b: Int) extends K { val isOrdered = true }
foldMapV(v, new Monoid[K] {
override def op(a1: K, a2: K): K = (a1, a2) match {
case (Disordered(), _) => Disordered()
case (_, Disordered()) => Disordered()
case (Identity(), _) => a2
case (_, Identity()) => a1
case (Range(x1, x2), Range(y1, y2)) =>
if (y1 >= x2) Range(x1, y2)
else Disordered()
}
override def zero: K = Identity()
})(x => Range(x, x)).isOrdered
}
object WC {
def split(str: String): Array[String] = {
val ks = List(0) ++ (0 until str.length).filter(i => str.charAt(i).isSpaceChar) ++ List(str.length)
ks.zip(ks.drop(1)).map({case (a,b) => str.substring(a, b)}).toArray
}
def analyze(str: String): WC = {
val parts = split(str)
if (parts.isEmpty) Stub("")
else if (parts.length == 1) Stub(parts.head)
else Part(parts.head, parts.length - 2, parts.last)
}
}
sealed trait WC
case class Stub(chars: String) extends WC
case class Part(lStub: String, words: Int, rStub: String) extends WC
// Exercise 10.10
val wcMonoid = new Monoid[WC] {
override def op(a1: WC, a2: WC): WC = (a1, a2) match {
case (Stub(s1), Stub(s2)) => Stub(s1+s2)
case (Part(ls1, w1, rs1), Part(ls2, w2, rs2)) => Part(ls1, w1 + w2 + 1, rs2)
case (Part(ls, w, rs), Stub(s)) => Part(ls, w, rs+s)
case (Stub(s), Part(ls, w, rs)) => Part(s+ls, w, rs)
}
override def zero: WC = Stub("")
}
// Exercise 10.11
def countWords(str: String, chunkSize: Int): Int = {
val m = wcMonoid
def rec(str: String): WC =
if (str.length > chunkSize) str.splitAt(str.length / 2) match {
case (s1, s2) => m.op(rec(s1), rec(s2))
}
else WC.analyze(str)
def k(str: String): Int = if (str == "") 0 else 1
rec(str) match {
case Stub(s) => k(s)
case Part(ls, w, rs) => w + k(ls) + k(rs)
}
}
trait Foldable[F[_]] {
def foldRight[A,B](as: F[A])(z: B)(f: (A,B) => B): B
def foldLeft[A,B](as: F[A])(z: B)(f: (B,A) => B): B
def foldMap[A,B](as: F[A])(f: A => B)(m: Monoid[B]): B
def concatenate[A](as: F[A])(m: Monoid[A]): A = foldMap(as)(Predef.identity)(m)
// Exercise 10.15
def toList[A](fa: F[A]): List[A] =
foldMap(fa)(a => List(a))(listMonoid)
}
// Exercise 10.12
def foldableList[A] = new Foldable[List[A]] {
override def foldRight[A, B](as: List[A])(z: B)(f: (A, B) => B): B = as.foldRight(z)(f)
override def foldLeft[A, B](as: List[A])(z: B)(f: (B, A) => B): B = as.foldLeft(z)(f)
override def foldMap[A, B](as: List[A])(f: (A) => B)(m: Monoid[B]): B = Monoids.foldMap(as, m)(f)
}
def foldableIndexSeq[A]= new Foldable[IndexedSeq[A]] {
override def foldRight[A, B](as: IndexedSeq[A])(z: B)(f: (A, B) => B): B = as.foldRight(z)(f)
override def foldLeft[A, B](as: IndexedSeq[A])(z: B)(f: (B, A) => B): B = as.foldLeft(z)(f)
override def foldMap[A, B](as: IndexedSeq[A])(f: (A) => B)(m: Monoid[B]): B = Monoids.foldMapV(as, m)(f)
}
def foldableStream[A] = new Foldable[Stream[A]] {
override def foldRight[A, B](as: Stream[A])(z: B)(f: (A, B) => B): B = as.foldRight(z)(f)
override def foldLeft[A, B](as: Stream[A])(z: B)(f: (B, A) => B): B = as.foldLeft(z)(f)
override def foldMap[A, B](as: Stream[A])(f: (A) => B)(m: Monoid[B]): B = as.map(f).foldLeft(m.zero)(m.op)
}
sealed trait Tree[+A]
case class Leaf[A](value: A) extends Tree[A]
case class Branch[A](left: Tree[A], right: Tree[A]) extends Tree[A]
// Exercise 10.13
def foldableTree[A] = new Foldable[Tree[A]] {
override def foldRight[A, B](as: Tree[A])(z: B)(f: (A, B) => B): B = as match {
case Leaf(a) => f(a, z)
case Branch(l, r) => foldRight(l)(foldRight(r)(z)(f))(f)
}
override def foldLeft[A, B](as: Tree[A])(z: B)(f: (B, A) => B): B = as match {
case Leaf(a) => f(z, a)
case Branch(l, r) => foldLeft(r)(foldLeft(l)(z)(f))(f)
}
override def foldMap[A, B](as: Tree[A])(f: (A) => B)(m: Monoid[B]): B = as match {
case Leaf(a) => f(a)
case Branch(l, r) => m.op(foldMap(l)(f)(m), foldMap(r)(f)(m))
}
}
// Exercise 10.14
def foldableOption[A] = new Foldable[Option[A]] {
override def foldRight[A, B](as: Option[A])(z: B)(f: (A, B) => B): B = as.foldRight(z)(f)
override def foldLeft[A, B](as: Option[A])(z: B)(f: (B, A) => B): B = as.foldLeft(z)(f)
override def foldMap[A, B](as: Option[A])(f: (A) => B)(m: Monoid[B]): B = as.map(f).foldLeft(m.zero)(m.op)
}
// Exercise 10.16
def productMonoid[A,B](ma: Monoid[A], mb: Monoid[B]): Monoid[(A,B)] = new Monoid[(A,B)] {
override def op(x: (A, B), y: (A, B)): (A, B) = (x, y) match {
case ((a1, b1), (a2, b2)) => (ma.op(a1, a2), mb.op(b1, b2))
}
override def zero: (A, B) = (ma.zero, mb.zero)
}
// Exercise 10.17
def functionMonoid[A,B](mb: Monoid[B]) = new Monoid[A => B] {
override def op(a1: (A) => B, a2: (A) => B): (A) => B = x => mb.op(a1(x), a2(x))
override def zero: (A) => B = _ => mb.zero
}
// Exercise 10.18
def bag[A](as: IndexedSeq[A]): Map[A, Int] = {
val m = new Monoid[Map[A, Int]] {
override def op(a1: Map[A, Int], a2: Map[A, Int]): Map[A, Int] =
(a1.keySet ++ a2.keySet).foldLeft(zero) {
(acc, key) => acc.updated(key, a1.getOrElse(key, 0) + a2.getOrElse(key, 0))
}
override def zero: Map[A, Int] = Map()
}
foldableIndexSeq.foldMap(as)(x => Map(x -> 1))(m)
}
}
object MonoidsPlayground {
import Monoids._
def main(args: Array[String]) {
// println(ordered(Vector()))
// println(ordered(Vector(10)))
// println(ordered(Vector(10, 20)))
// println(ordered(Vector(10, 20, 30, 30, 40)))
// println(ordered(Vector(10, 20, 31, 30, 40)))
println(countWords("the quick brown fox", 6))
println(countWords("the quick brown fox", 2))
println(countWords("the quick brown fox", 100))
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment