diff --git a/src/main/scala/fpspeedrun/Eq.scala b/src/main/scala/fpspeedrun/Eq.scala index 1f0649b..3060b53 100644 --- a/src/main/scala/fpspeedrun/Eq.scala +++ b/src/main/scala/fpspeedrun/Eq.scala @@ -1,4 +1,5 @@ package fpspeedrun + import simulacrum.{op, typeclass} import scala.annotation.tailrec @@ -13,6 +14,7 @@ trait Eq[T] { } object Eq extends StdEqInstances { + import ops._ def fromEquals[A]: Eq[A] = _ == _ @@ -32,10 +34,19 @@ object Eq extends StdEqInstances { case y :: yt => x === y && go(xt, yt) } } + go } } -trait StdEqInstances extends StdOrdInstances[Eq]{ - implicit def eitherEq[A: Eq, B: Eq]: Eq[Either[A, B]] = ??? +trait StdEqInstances extends StdOrdInstances[Eq] { + + import fpspeedrun.syntax.eq._ + + implicit def eitherEq[A: Eq, B: Eq]: Eq[Either[A, B]] = + (x: Either[A, B], y: Either[A, B]) => (x, y) match { + case (Right(xe), Right(ye)) => xe === ye + case (Left(xe), Left(ye)) => xe === ye + case _ => false + } } diff --git a/src/main/scala/fpspeedrun/Monoid.scala b/src/main/scala/fpspeedrun/Monoid.scala index bde003a..a98ce77 100644 --- a/src/main/scala/fpspeedrun/Monoid.scala +++ b/src/main/scala/fpspeedrun/Monoid.scala @@ -1,7 +1,8 @@ package fpspeedrun import fpspeedrun.Iso.{Wrapper, WrapperCompanion} +import fpspeedrun.syntax.num._ +import fpspeedrun.syntax.semigroup._ import simulacrum.typeclass -import syntax.semigroup._ @typeclass trait Monoid[A] extends Semigroup[A] with Default[A]{ @@ -21,19 +22,31 @@ object Monoid extends StdMonoidInstances[Monoid] { final case class Endo[A](run: A => A) extends AnyVal object Endo{ - implicit def endoMonoid[A]: Monoid[Endo[A]] = ??? + implicit def endoMonoid[A]: Monoid[Endo[A]] = new Monoid[Endo[A]] { + override def empty: Endo[A] = Endo(identity) + + override def combine(x: Endo[A], y: Endo[A]): Endo[A] = Endo(y.run compose x.run) + } } final case class Sum[T](value: T) extends AnyVal with Wrapper[T] object Sum extends WrapperCompanion[Sum] { - implicit def sumMonoid[T: Num]: Monoid[Sum[T]] = ??? + implicit def sumMonoid[T: Num]: Monoid[Sum[T]] = new Monoid[Sum[T]] { + override def empty: Sum[T] = Sum(zero) + + override def combine(x: Sum[T], y: Sum[T]): Sum[T] = Sum(x.value plus y.value) + } } final case class Prod[T](value: T) extends AnyVal with Wrapper[T] object Prod extends WrapperCompanion[Prod] { - implicit def prodMonoid[T: Num]: Monoid[Prod[T]] = ??? + implicit def prodMonoid[T: Num]: Monoid[Prod[T]] = new Monoid[Prod[T]] { + override def empty: Prod[T] = Prod(one) + + override def combine(x: Prod[T], y: Prod[T]): Prod[T] = Prod(x.value * y.value) + } } @@ -48,5 +61,9 @@ trait StdMonoidInstances[TC[x] >: Monoid[x]] { override def combine(x: List[A], y: List[A]): List[A] = x ::: y } - final implicit def vectorMonoid[A]: TC[Vector[A]] = ??? + final implicit def vectorMonoid[A]: TC[Vector[A]] = new Monoid[Vector[A]] { + override def empty: Vector[A] = Vector.empty + + override def combine(x: Vector[A], y: Vector[A]): Vector[A] = x ++ y + } } diff --git a/src/main/scala/fpspeedrun/Ord.scala b/src/main/scala/fpspeedrun/Ord.scala index f00201e..ed7a990 100644 --- a/src/main/scala/fpspeedrun/Ord.scala +++ b/src/main/scala/fpspeedrun/Ord.scala @@ -1,8 +1,8 @@ package fpspeedrun -import fpspeedrun.Ord.{Compare, byOrdering} import fpspeedrun.Ord.Compare.{EQ, GT, LT} +import fpspeedrun.Ord.{Compare, byOrdering} +import fpspeedrun.syntax.eq._ import simulacrum.{op, typeclass} -import syntax.eq._ import scala.annotation.tailrec import scala.collection.immutable.Seq @@ -71,5 +71,16 @@ object Ord extends StdOrdInstances[Ord] { trait StdOrdInstances[TC[t] >: Ord[t]] extends StdNumInstances[TC]{ final implicit val stringOrd: TC[String] = byOrdering - final implicit def optionOrd[A: Ord]: TC[Option[A]] = ??? + + final implicit def optionOrd[A: Ord]: TC[Option[A]] = new Ord[Option[A]] { + + import fpspeedrun.syntax.ord._ + + override def compare(x: Option[A], y: Option[A]): Compare = (x, y) match { + case (Some(xo), Some(yo)) => xo compare yo + case (Some(_), None) => GT + case (None, Some(_)) => LT + case (None, None) => EQ + } + } } \ No newline at end of file diff --git a/src/main/scala/fpspeedrun/ZipList.scala b/src/main/scala/fpspeedrun/ZipList.scala index 607767d..2116884 100644 --- a/src/main/scala/fpspeedrun/ZipList.scala +++ b/src/main/scala/fpspeedrun/ZipList.scala @@ -1,5 +1,13 @@ package fpspeedrun +import fpspeedrun.Eq._ +import fpspeedrun.syntax.eq._ +import fpspeedrun.syntax.frac._ +import fpspeedrun.syntax.integ._ +import fpspeedrun.syntax.num._ +import fpspeedrun.syntax.ord._ +import fpspeedrun.syntax.semigroup._ + trait ZipList[A] { def value: Either[A, List[A]] @@ -7,15 +15,19 @@ trait ZipList[A] { } object ZipList { + final case class Repeat[A](single: A) extends ZipList[A] { override def value = Left(single) + override def zipWith[B, C](that: ZipList[B])(f: (A, B) => C): ZipList[C] = that match { case Repeat(b) => Repeat(f(single, b)) case Finite(xs) => Finite(xs.map(f(single, _))) } } + final case class Finite[A](list: List[A]) extends ZipList[A] { override def value = Right(list) + override def zipWith[B, C](that: ZipList[B])(f: (A, B) => C): ZipList[C] = that match { case Repeat(b) => Finite(list.map(f(_, b))) case Finite(ys) => Finite((list, ys).zipped.map(f)) @@ -23,19 +35,86 @@ object ZipList { } def apply[A](list: List[A]): ZipList[A] = Finite(list) + def repeat[A](value: A): ZipList[A] = Repeat(value) - implicit def zipListSemigroup[A: Semigroup]: Semigroup[ZipList[A]] = ??? + implicit def zipListSemigroup[A: Semigroup]: Semigroup[ZipList[A]] = + (x: ZipList[A], y: ZipList[A]) => x.zipWith(y)(_ |+| _) + + implicit def zipListMonoid[A: Monoid]: Monoid[ZipList[A]] = new Monoid[ZipList[A]] { + override def empty: ZipList[A] = repeat(Monoid[A].empty) + + override def combine(x: ZipList[A], y: ZipList[A]): ZipList[A] = + x.zipWith(y)(_ |+| _) + } + + implicit def zipListEq[A: Eq]: Eq[ZipList[A]] = + (x: ZipList[A], y: ZipList[A]) => x.value === y.value + + implicit def zipListOrd[A: Ord]: Ord[ZipList[A]] = + (x: ZipList[A], y: ZipList[A]) => (x.value, y.value) match { + case (Right(xo), Right(yo)) => xo <=> yo + case (Left(xo), Right(yo)) => List.fill(yo.length)(xo) <=> yo + case (Right(xo), Left(yo)) => xo <=> List.fill(xo.length)(yo) + case (Left(xo), Left(yo)) => xo <=> yo + } + + implicit def zipListNum[A: Num]: Num[ZipList[A]] = new Num[ZipList[A]] { + override def fromInt(x: Int): ZipList[A] = Repeat(x.toNum) + + override def plus(x: ZipList[A], y: ZipList[A]): ZipList[A] = x.zipWith(y)(_ + _) + + override def times(x: ZipList[A], y: ZipList[A]): ZipList[A] = x.zipWith(y)(_ * _) + + override def compare(x: ZipList[A], y: ZipList[A]): Ord.Compare = + (x.value, y.value) match { + case (Right(xo), Right(yo)) => xo <=> yo + case (Left(xo), Right(yo)) => List.fill(yo.length)(xo) <=> yo + case (Right(xo), Left(yo)) => xo <=> List.fill(xo.length)(yo) + case (Left(xo), Left(yo)) => xo <=> yo + } + + } + + implicit def zipListInteg[A: Integ]: Integ[ZipList[A]] = new Integ[ZipList[A]] { + override def quotRem(x: ZipList[A], y: ZipList[A]): (ZipList[A], ZipList[A]) = + x.zipWith(y)(_ quotRem _).value match { + case Left((q, r)) => Repeat(q) -> Repeat(r) + case Right(qrs) => qrs.unzip match { + case (l, r) => ZipList(l) -> ZipList(r) + } + } + + override def fromInt(x: Int): ZipList[A] = Repeat(x.toNum) + + override def plus(x: ZipList[A], y: ZipList[A]): ZipList[A] = x.zipWith(y)(_ plus _) - implicit def zipListMonoid[A: Monoid]: Monoid[ZipList[A]] = ??? + override def times(x: ZipList[A], y: ZipList[A]): ZipList[A] = x.zipWith(y)(_ times _) - implicit def zipListEq[A: Eq]: Eq[ZipList[A]] = ??? + override def compare(x: ZipList[A], y: ZipList[A]): Ord.Compare = + (x.value, y.value) match { + case (Right(xo), Right(yo)) => xo <=> yo + case (Left(xo), Right(yo)) => List.fill(yo.length)(xo) <=> yo + case (Right(xo), Left(yo)) => xo <=> List.fill(xo.length)(yo) + case (Left(xo), Left(yo)) => xo <=> yo + } + } + + implicit def zipListFrac[A: Frac]: Frac[ZipList[A]] = new Frac[ZipList[A]] { + override def div(x: ZipList[A], y: ZipList[A]): ZipList[A] = x.zipWith(y)(_ / _) - implicit def zipListOrd[A: Ord]: Ord[ZipList[A]] = ??? + override def fromInt(x: Int): ZipList[A] = fromInt(x) - implicit def zipListNum[A: Num]: Num[ZipList[A]] = ??? + override def plus(x: ZipList[A], y: ZipList[A]): ZipList[A] = x.zipWith(y)(_ plus _) - implicit def zipListInteg[A: Integ]: Integ[ZipList[A]] = ??? + override def times(x: ZipList[A], y: ZipList[A]): ZipList[A] = x.zipWith(y)(_ times _) - implicit def zipListFrac[A: Frac]: Frac[ZipList[A]] = ??? + override def compare(x: ZipList[A], y: ZipList[A]): Ord.Compare = + (x.value, y.value) match { + case (Right(xo), Right(yo)) => xo <=> yo + case (Left(xo), Right(yo)) => List.fill(yo.length)(xo) <=> yo + case (Right(xo), Left(yo)) => xo <=> List.fill(xo.length)(yo) + case (Left(xo), Left(yo)) => xo <=> yo + } + } } diff --git a/src/main/scala/fpspeedrun/syntax/package.scala b/src/main/scala/fpspeedrun/syntax/package.scala index 4682d78..a17c64f 100644 --- a/src/main/scala/fpspeedrun/syntax/package.scala +++ b/src/main/scala/fpspeedrun/syntax/package.scala @@ -48,13 +48,14 @@ object semigroup extends Semigroup.ToSemigroupOps { } object monoid extends Monoid.ToMonoidOps{ - def empty[T: Monoid]: T = ??? + def empty[T: Monoid]: T = Monoid[T].empty implicit class ListOps[A](val xs: List[A]) extends AnyVal{ - def foldAll(implicit mon: Monoid[A]): A = ??? + def foldAll(implicit mon: Monoid[A]): A = xs.foldLeft(mon.empty)(mon.combine) - def foldMap[B: Monoid](f: A => B): B = ??? + def foldMap[B: Monoid](f: A => B): B = xs.map(f).foldAll - def foldVia[F[_]](implicit iso: Iso[A, F[A]], mon: Monoid[F[A]]): A = ??? + def foldVia[F[_]](implicit iso: Iso[A, F[A]], mon: Monoid[F[A]]): A = + xs.foldLeft(iso.unwrap(mon.empty))((x, y) => iso.unwrap(mon.combine(iso.wrap(x), iso.wrap(y)))) } }