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
12 changes: 7 additions & 5 deletions src/main/scala/fpspeedrun/foldables/Delay.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ trait Delay[A] {
def delay(x: => A): A
}

sealed trait EvalDelayInstance{
implicit def evalDelay[A]: Delay[Eval[A]] = ???
sealed trait EvalDelayInstance {
implicit def evalDelay[A]: Delay[Eval[A]] = new Delay[Eval[A]] {
override def delay(x: => Eval[A]): Eval[A] = Eval.defer(x)
}
}
object Delay extends EvalDelayInstance {
implicit def dual[A](implicit delay: Delay[A]): Delay[Dual[A]] = ???
implicit def dual[A](implicit d: Delay[A]): Delay[Dual[A]] = new Delay[Dual[A]] {
override def delay(x: => Dual[A]): Dual[A] = Dual(d.delay(x.getDual))
}
}


22 changes: 17 additions & 5 deletions src/main/scala/fpspeedrun/foldables/FoldMapDelay.scala
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
package fpspeedrun
package foldables

import cats.{Eval, Foldable, Monoid}
import newts.Dual
import cats.{ Eval, Foldable, Monoid }
import fpspeedrun.foldables.LzEndo._
import syntax.delay._
import cats.syntax.semigroup._
import newts.Dual

abstract class FoldMapDelay[F[_]] extends Foldable[F] {
def foldMapDelay[A, B: Monoid: Delay](fa: F[A])(f: A => B): B

override def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = ???
override def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = ???
override def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = {
foldMapDelay[A, LzEndo[B]](fa)(a => LzEndo[B](ev => ev.map(internal => f(internal, a))))
.run(Eval.now(b)).value
}
override def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
foldMapDelay[A, Dual[LzEndo[B]]](fa)(a => Dual(LzEndo[B](f.curried(a)))).getDual.run(lb)
}
}

object FoldMapDelay {

implicit val streamInstance: Foldable[Stream] = ???
implicit val streamInstance: Foldable[Stream] = new FoldMapDelay[Stream] {
override def foldMapDelay[A, B: Monoid : Delay](fa: Stream[A])(f: A => B): B = {
fa.headOption.fold(Monoid[B].empty) { h =>
f(h) |+| foldMapDelay(fa.tail)(f).delay
}
}
}
}
27 changes: 22 additions & 5 deletions src/main/scala/fpspeedrun/foldables/Iter.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
package fpspeedrun.foldables
import cats.Foldable
import cats.Eval
import cats.instances.stream._
import cats.syntax.foldable._

final case class Iter[F[_]: Foldable, A](x: F[A]) extends Iterable[A]{
override def iterator: Iterator[A] = ???
override def iterator: Iterator[A] = {
Foldable[F].foldRight(x, Eval.now(Iterator[A]())) { (v, acc) =>
Eval.now {
val as = Iterator(v)
as ++ acc.value
}
}.value
}
}

final case class Fold[A](xs: Iterable[A])

object Fold{
implicit val foldable: Foldable[Fold] = ???
}
final case class Fold[A](xs: Iterable[A])

object Fold {
implicit val foldable: Foldable[Fold] = new Foldable[Fold] {
override def foldLeft[A, B](fa: Fold[A], b: B)(f: (B, A) => B): B = {
fa.xs.foldLeft(b)(f)
}

override def foldRight[A, B](fa: Fold[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
fa.xs.toStream.foldr(lb)(f)
}
}
}
11 changes: 10 additions & 1 deletion src/main/scala/fpspeedrun/foldables/LzEndo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,14 @@ import cats.{Eval, Monoid}
final case class LzEndo[A](run: Eval[A] => Eval[A]) extends AnyVal

object LzEndo {
implicit def endoInstance[A]: Monoid[LzEndo[A]] with Delay[LzEndo[A]] = ???
implicit def endoInstance[A]: Monoid[LzEndo[A]] with Delay[LzEndo[A]] =
new Monoid[LzEndo[A]] with Delay[LzEndo[A]] {
override def empty: LzEndo[A] = LzEndo(identity)

override def delay(x: => LzEndo[A]): LzEndo[A] = LzEndo(y => Eval.defer(x.run(y)))

override def combine(x: LzEndo[A], y: LzEndo[A]): LzEndo[A] = {
LzEndo(ev => Eval.later(()).flatMap(_ => Eval.defer(y.run(Eval.defer(x.run(ev))))))
}
}
}
33 changes: 33 additions & 0 deletions src/main/scala/fpspeedrun/foldables/StringWrap.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package fpspeedrun.foldables

import cats.{Eval, Foldable, Monoid}
import fpspeedrun.foldables.LzEndo._
import newts.Dual

case class StringWrap[E](str: String)(implicit ev: Char =:= E) {
def foldMap[B: Monoid](f: E => B): B = {
str.map(ch => f(ev(ch))).foldLeft(Monoid[B].empty)(Monoid[B].combine)
}
}

object StringWrap {
implicit def foldable = new Foldable[StringWrap[?]] {

override def foldLeft[A, B](fa: StringWrap[A], b: B)(f: (B, A) => B): B = {
fa.foldMap[LzEndo[B]](a => LzEndo[B](_.map(f(_, a)))).run(Eval.now(b)).value
}

override def foldRight[A, B](fa: StringWrap[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
fa.foldMap[Dual[LzEndo[B]]](a => Dual(LzEndo(ev => f(a, ev)))).getDual.run(lb)
}
}
}


//object Main3 extends App {
// import StringWrap._
// import cats.syntax.foldable._
//
// require(StringWrap("asdqwe").foldLeft("A") { (acc, v) => v + acc } == "ewqdsaA")
// require(StringWrap("asdqwe").foldRight(Eval.now("A")) { (v, acc) => acc.map(_ + v) }.value == "Aewqdsa")
//}
62 changes: 56 additions & 6 deletions src/main/scala/fpspeedrun/foldables/streams.scala
Original file line number Diff line number Diff line change
@@ -1,26 +1,76 @@
package fpspeedrun.foldables
import cats.Foldable
import cats.{Eval, Foldable}
import cats.syntax.foldable._

final case class Filter[F[_], A](fa: F[A], p: A => Boolean)

object Filter {
implicit def foldable[F[_]: Foldable]: Foldable[Filter[F, ?]] = ???
implicit def foldable[F[_]: Foldable]: Foldable[Filter[F, ?]] = new Foldable[Filter[F, ?]] {
override def foldLeft[A, B](fa: Filter[F, A], b: B)(f: (B, A) => B): B = {
fa.fa.foldLeft(b)((acc, el) => if (fa.p(el)) f(acc, el) else acc)
}
override def foldRight[A, B](fa: Filter[F, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
fa.fa.foldRight(lb)((el, acc) => if (fa.p(el)) f(el, acc) else acc)
}
}
}

final case class Map[F[_], A, B](fa: F[A], p: A => B)

object Map {
implicit def foldable[F[_]: Foldable, A]: Foldable[Map[F, A, ?]] = ???
implicit def foldable[F[_]: Foldable, X]: Foldable[Map[F, X, ?]] = new Foldable[Map[F, X, ?]] {
override def foldLeft[A, B](fa: Map[F, X, A], b: B)(f: (B, A) => B): B = {
fa.fa.foldLeft(b) { (acc, el) => f(acc, fa.p(el)) }
}

override def foldRight[A, B](fa: Map[F, X, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
fa.fa.foldRight(lb) { (el, acc) => f(fa.p(el), acc) }
}
}
}

final case class Collect[F[_], A, B](fa: F[A], pf: PartialFunction[A, B])

object Collect {
implicit def foldable[F[_]: Foldable, A]: Foldable[Collect[F, A, ?]] = ???
implicit def foldable[F[_]: Foldable, X]: Foldable[Collect[F, X, ?]] = new Foldable[Collect[F, X, ?]] {
override def foldLeft[A, B](fa: Collect[F, X, A], b: B)(f: (B, A) => B): B = {
fa.fa.foldLeft(b) { (acc, el) => fa.pf.lift(el).fold(acc)(f(acc, _)) }
}

override def foldRight[A, B](fa: Collect[F, X, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
fa.fa.foldRight(lb){ (el, acc) => fa.pf.lift(el).fold(acc)(f(_, acc)) }
}
}
}

final case class FlatMap[F[_], A, G[_], B](fa: F[A], f: A => G[B])
final case class FlatMap[F[_], X, G[_], A](fa: F[X], f: X => G[A])

object FlatMap {
implicit def foldable[F[_]: Foldable, A, G[_]: Foldable]: Foldable[FlatMap[F, A, G, ?]] = ???
implicit def foldable[F[_]: Foldable, X, G[_]: Foldable]: Foldable[FlatMap[F, X, G, ?]] = new Foldable[FlatMap[F, X, G, ?]] {
override def foldLeft[A, B](fa: FlatMap[F, X, G, A], b: B)(f: (B, A) => B): B = {
fa.fa.foldLeft(b)((acc, x) => fa.f(x).foldLeft(acc)(f))
}

override def foldRight[A, B](fa: FlatMap[F, X, G, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
fa.fa.foldRight(lb)((x, acc) => fa.f(x).foldRight(acc)(f))
}
}
}

object Main extends App {
import Collect._
import FlatMap._

import cats.instances.stream._
import cats.instances.list._

val pf: PartialFunction[Int, Int] = { case x: Int if x > 3 => x }
val collect: Collect[List, Int, Int] = Collect(List(1,2,3,4,5), pf)
require(Iter(collect).iterator.toStream.foldl(0)(_ + _) == 9)
require(Iter(collect).iterator.toStream.foldr(Eval.now(0))((x, acc) => acc.map(_ + x)).value == 9)

val f = (x: Int) => List[Int](x, x)
val flatMap = FlatMap[List, Int, List, Int](List(1,2,3,4,5), f)
require(Iter(flatMap).iterator.toStream.foldl(0)(_ + _) == 30)
require(Iter(flatMap).iterator.toStream.foldr(Eval.now(0))((x, acc) => acc.map(_ + x)).value == 30)
}
7 changes: 4 additions & 3 deletions src/test/scala/fpspeedrun/foldables/FoldMapDelayApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ object FoldMapDelayApp {
.value

def main(args: Array[String]): Unit = {
// println(sum(Stream.range[BigInt](0, 100001)))
// println(sumN(5)(Stream.range(0, 11).map{x => println(x); x * 2 + 1}))
// println(sumN(10001)(Stream.from(0)))
println(sum(Stream.range[BigInt](0, 100001)))
println(sumN(5)(Stream.range(0, 11).map{x => println(x); x * 2 + 1}))
println(sumN(10001)(Stream.from(0)))
println(Stream.range(0, 11).foldl(0)((acc, x) => acc + x))
}
}