Skip to content

Instantly share code, notes, and snippets.

@bpk-t
Last active April 11, 2017 13:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bpk-t/492637718b6466386f29bc8d2026ef9c to your computer and use it in GitHub Desktop.
Save bpk-t/492637718b6466386f29bc8d2026ef9c to your computer and use it in GitHub Desktop.
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