Skip to content

Instantly share code, notes, and snippets.

@sshark
Last active August 29, 2015 14:27
Show Gist options
  • Select an option

  • Save sshark/a8babe2ad553843b0cc3 to your computer and use it in GitHub Desktop.

Select an option

Save sshark/a8babe2ad553843b0cc3 to your computer and use it in GitHub Desktop.
Using monoids with Map and Option as value. Does it make sense to have Option as value insteadof the actual value because the Map can return Option. This code does not compile
// following http://inoio.de/blog/2014/07/19/type-class-101-semigroup/
trait Semigroup[A] {
def append(a: A, b: A): A
}
trait Monoid[A] extends Semigroup[A] {
def zero: A
}
implicit val intSemigroup = new Semigroup[Int] {
def append(a: Int, b: Int) = a + b
}
implicit val intMonoid = new Monoid[Int] {
def append(a: Int, b: Int) = a + b
def zero = 0
}
object Semigroup {
def apply[A](implicit F: Semigroup[A]) = F
}
object Monoid {
def apply[A](implicit F: Monoid[A]) = F
}
Semigroup.apply[Int].append(1, 2)
Semigroup[Int].append(1, 2)
Monoid[Int].append(2,3)
trait SemigroupSyntax[A] {
def self: A
def F: Semigroup[A]
def |+|(b: A): A = append(b)
// alias for append
def append(b: A): A = F.append(self, b)
}
trait MonoidSyntax[A] extends SemigroupSyntax[A] {
def zero: A
def F: Monoid[A]
}
implicit def ToMonoidOps[A: Monoid](a: A): MonoidSyntax[A] =
new MonoidSyntax[A] {
def self: A = a
def F: Monoid[A] = implicitly[Monoid[A]]
def zero = F.zero
}
3 |+| 4 // 7
implicit def optionInstances[A: Monoid] = new Monoid[Option[A]] {
def append(a: Option[A], b: Option[A]): Option[A] = {
(a, b) match {
case (Some(a1), Some(b1)) => Some(Monoid[A].append(a1, b1))
case (Some(_), None) => a
case (None, Some(_)) => b
case _ => None
}
}
def zero = None
}
Option(30).append(Option(40)) == (Option(30) |+| Option(40)) // true; both equals to Option(70)
implicit def mapInstances[K, V: Monoid] = new Monoid[Map[K, V]] {
def append(a: Map[K, V], b: Map[K, V]): Map[K, V] = {
(a, b) match {
case (a: Map[K, V], b: Map[K, V]) => a.foldLeft(b) {
case (m, v) =>
m + (v._1 -> Monoid[V].append(m.getOrElse(v._1, Monoid[V].zero), v._2))
}
}
}
def zero = Map.empty[K, V]
}
implicit def mapOptionInstances[K, V: Monoid[Option[_]]] = new Monoid[Map[K, Option[V]]] {
def append(a: Map[K, Option[V]], b: Map[K, Option[V]]): Map[K, Option[V]] = {
(a, b) match {
case (a: Map[K, Option[V]], b: Map[K, Option[V]]) => a.foldLeft(b) {
case (m, v) =>
m + (v._1 -> Monoid[Option[V]].append(m.getOrElse(v._1, Monoid[Option[V]].zero), v._2))
}
}
}
def zero = Map.empty[K, Option[V]]
}
val m = Map[Symbol, Int]()
val n = Map('a -> 1, 'b -> 2)
val x = m |+| n
val a = Map('a -> 2, 'b -> 3, 'c -> 7)
val b = Map('a -> 1, 'b -> 2)
val answer = Map('a -> 3, 'b -> 5, 'c -> 7)
(a |+| b) == answer
val aOpt = Map('a -> Some(2), 'b -> Some(3), 'c -> Some(7))
val bOpt = Map('a -> Some(1), 'b -> Some(2))
val ansOpt = Map('a -> Some(3), 'b -> Some(5), 'c -> Some(7))
(aOpt |+| bOpt) == ansOpt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment