Last active
April 11, 2017 13:53
-
-
Save bpk-t/492637718b6466386f29bc8d2026ef9c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait Monoid[A] { | |
def op(a1: A, a2 : A): A | |
def zero: A | |
} | |
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)(mb: Monoid[B]):B | |
def concatenate[A](as: F[A])(m: Monoid[A]): A | |
// 10.15 | |
def toList[A](fa: F[A]): List[A] = foldLeft(fa)(List.empty[A])((acc, x) => acc :+ x) | |
} | |
object Main extends App { | |
val stringMonoid = new Monoid[String] { | |
override def op(a1: String, a2: String): String = a1 + a2 | |
override def zero: String = "" | |
} | |
def listMonoid[A] = new Monoid[List[A]] { | |
override def op(a1: List[A], a2: List[A]): List[A] = a1 ++ a2 | |
override def zero: List[A] = Nil | |
} | |
// 10.1 | |
val intAddition = new Monoid[Int] { | |
override def op(a1: Int, a2: Int): Int = a1 + a2 | |
override def zero: Int = 0 | |
} | |
// 10.1 | |
val intMultiplication = new Monoid[Int] { | |
override def op(a1: Int, a2: Int): Int = a1 * a2 | |
override def zero: Int = 1 | |
} | |
// 10.1 | |
val booleanOr = new Monoid[Boolean] { | |
override def op(a1: Boolean, a2: Boolean): Boolean = a1 || a2 | |
override def zero: Boolean = false | |
} | |
// 10.1 | |
val booleanAnd = new Monoid[Boolean] { | |
override def op(a1: Boolean, a2: Boolean): Boolean = a1 && a2 | |
override def zero: Boolean = true | |
} | |
// 10.2 | |
def optionMonoid[A] = new Monoid[Option[A]] { | |
override def op(a1: Option[A], a2: Option[A]): Option[A] = a1.orElse(a2) | |
override def zero: Option[A] = None | |
} | |
// 10.3 | |
def endoMonoid[A] = new Monoid[A => A] { | |
override def op(a1: (A) => A, a2: (A) => A): (A) => A = a1.compose(a2) | |
override def zero: (A) => A = identity | |
} | |
// 10.4 | |
//def monoidLaws[A](m: Monoid[A], gen: Gen[A]): Prop | |
val words = List("Hic", "Est", "Index") | |
val s = words.foldRight(stringMonoid.zero)(stringMonoid.op) | |
val t = words.foldLeft(stringMonoid.zero)(stringMonoid.op) | |
// 10.5 | |
def foldMap[A, B](as: List[A], m: Monoid[B])(f: A => B): B = as.foldLeft(m.zero)((acc, x) => m.op(acc, f(x))) | |
// 10.12 | |
val foldableList = new Foldable[List] { | |
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)(mb: Monoid[B]): B = as.foldLeft(mb.zero)((acc, x) => mb.op(acc, f(x))) | |
override def concatenate[A](as: List[A])(m: Monoid[A]): A = as.foldLeft(m.zero)(m.op) | |
} | |
// 10.12 | |
val foldableIndexedSeq = new Foldable[IndexedSeq] { | |
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)(mb: Monoid[B]): B = as.foldLeft(mb.zero)((acc, x) => mb.op(acc, f(x))) | |
override def concatenate[A](as: IndexedSeq[A])(m: Monoid[A]): A = as.foldLeft(m.zero)(m.op) | |
} | |
// 10.12 | |
val foldableStream = new Foldable[Stream] { | |
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)(mb: Monoid[B]): B = as.foldLeft(mb.zero)((acc, x) => mb.op(acc, f(x))) | |
override def concatenate[A](as: Stream[A])(m: Monoid[A]): A = as.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] | |
// 10.13 | |
val foldableTree = new Foldable[Tree] { | |
override def foldRight[A, B](as: Tree[A])(z: B)(f: (A, B) => B): B = as match { | |
case Leaf(v) => f(v, 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(v) => f(z, v) | |
case Branch(l, r) => foldLeft(r)(foldLeft(l)(z)(f))(f) | |
} | |
override def foldMap[A, B](as: Tree[A])(f: (A) => B)(mb: Monoid[B]): B = foldLeft(as)(mb.zero)((acc, x) => mb.op(acc, f(x))) | |
override def concatenate[A](as: Tree[A])(m: Monoid[A]): A = foldLeft(as)(m.zero)(m.op) | |
} | |
// 10.14 | |
val foldableOption = new Foldable[Option] { | |
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)(mb: Monoid[B]): B = as.foldLeft(mb.zero)((acc, x) => mb.op(acc, f(x))) | |
override def concatenate[A](as: Option[A])(m: Monoid[A]): A = as.foldLeft(m.zero)(m.op) | |
} | |
// 10.16 | |
def productMonoid[A, B](a: Monoid[A], b: Monoid[B]): Monoid[(A, B)] = new Monoid[(A, B)] { | |
override def op(a1: (A, B), a2: (A, B)): (A, B) = (a1, a2) match { | |
case ((a1a, a1b), (a2a, a2b)) => (a.op(a1a, a2a), b.op(a1b, a2b)) | |
} | |
override def zero: (A, B) = (a.zero, b.zero) | |
} | |
// 10.17 | |
def functionMonoid[A, B](b: Monoid[B]): Monoid[A => B] = new Monoid[(A) => B] { | |
override def op(a1: (A) => B, a2: (A) => B): A => B = x => b.op(a1(x), a2(x)) | |
override def zero: A => B = x => b.zero | |
} | |
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(0)) | |
} else { | |
val (l, r) = v.splitAt(v.length / 2) | |
m.op(foldMapV(l, m)(f), foldMapV(r, m)(f)) | |
} | |
} | |
def mapMergeMonoid[K, V](v: Monoid[V]): Monoid[Map[K, V]] = new Monoid[Map[K, V]] { | |
override def op(a1: Map[K, V], a2: Map[K, V]): Map[K, V] = | |
(a1.keySet ++ a2.keySet).foldLeft(zero) { (acc, k) => | |
acc.updated(k, v.op(a1.getOrElse(k, v.zero), a2.getOrElse(k, v.zero))) | |
} | |
override def zero: Map[K, V] = Map.empty[K, V] | |
} | |
// 10.18 | |
def bag[A](as: IndexedSeq[A]): Map[A, Int] = | |
foldMapV(as, mapMergeMonoid[A, Int](intAddition))((a: A) => Map(a -> 1)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment