Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/main/scala/fpspeedrun/Magma.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package fpspeedrun

trait Magma[T] {
def combine(x: T, y: T): T
}

sealed trait FreeMagma[T]
case class Leaf[T](x: T) extends FreeMagma[T]
case class Branch[T](x: FreeMagma[T], y: FreeMagma[T]) extends FreeMagma[T]

object FreeMagma {

def apply[T](x: T, y: T*): FreeMagma[T] = y match {
case Seq() => Leaf(x)
case Seq(a) => Branch(Leaf(x), Leaf(a))
case ys =>
val list = (x +: ys).reverse
val first +: second +: rest = list

rest.foldLeft(Branch(Leaf(second), Leaf(first)))((acc, e) => Branch(Leaf(e), acc))
}

implicit def freeMagmaMagma[T]: Magma[FreeMagma[T]] = (x: FreeMagma[T], y: FreeMagma[T]) => Branch(x, y)

}
19 changes: 19 additions & 0 deletions src/main/scala/fpspeedrun/syntax/package.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package fpspeedrun.syntax
import fpspeedrun._

import scala.annotation.tailrec

object eq extends Eq.ToEqOps

object ord extends Ord.ToOrdOps
Expand Down Expand Up @@ -45,6 +47,23 @@ object semigroup extends Semigroup.ToSemigroupOps {
def first: First[T] = First(x)
def last: Last[T] = Last(x)
}

implicit class FreeMagmaOps[T](val x: FreeMagma[T]) extends AnyVal {
@tailrec final def flat(x: List[FreeMagma[T]]): List[Leaf[T]] = {
val list: List[FreeMagma[T]] = x.flatMap {
case l@Leaf(_) => List(l)
case Branch(l, r) => List(l, r)
}

if (x.size == list.size) x.map(_.asInstanceOf[Leaf[T]])
else flat(list)
}

def reduceAll(implicit sg: Semigroup[T]): T = x match {
case Leaf(a) => a
case b@Branch(_, _) => flat(List(b)) map { case Leaf(l) => l } reduce sg.combine
}
}
}

object monoid extends Monoid.ToMonoidOps