Skip to content

Commit

Permalink
Split Free#foldStep into separate source files
Browse files Browse the repository at this point in the history
  • Loading branch information
LukaJCB committed Sep 14, 2020
1 parent d94e07a commit 8abdf3c
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 27 deletions.
39 changes: 39 additions & 0 deletions free/src/main/scala-2.x/cats/free/FreeFoldStep.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cats.free

import Free.{FlatMapped, Pure, Suspend}
import cats.{Eval, Foldable}

private[free] trait FreeFoldStep[S[_], A] {

def step: Free[S, A]

/**
* A combination of step and fold. May be used to define interpreters with custom
* (non-monoidial) control flow.
*/
final def foldStep[B](
onPure: A => B,
onSuspend: S[A] => B,
onFlatMapped: ((S[X], X => Free[S, A]) forSome { type X }) => B
): B =
this.step match {
case Pure(a) => onPure(a)
case Suspend(a) => onSuspend(a)
case FlatMapped(Suspend(fa), f) => onFlatMapped((fa, f))
case _ => sys.error("FlatMapped should be right associative after step")
}

final def foldLeft[B](fa: Free[S, A], b: B)(f: (B, A) => B)(implicit F: Foldable[S]): B =
fa.foldStep(
a => f(b, a),
fa => F.foldLeft(fa, b)(f),
{ case (fx, g) => F.foldLeft(fx, b)((bb, x) => foldLeft(g(x), bb)(f)) }
)

final def foldRight[B](fa: Free[S, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B])(implicit F: Foldable[S]): Eval[B] =
fa.foldStep(
a => f(a, lb),
fa => F.foldRight(fa, lb)(f),
{ case (fx, g) => F.foldRight(fx, lb)((a, lbb) => foldRight(g(a), lbb)(f)) }
)
}
41 changes: 41 additions & 0 deletions free/src/main/scala-3.x/cats/free/FreeFoldStep.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cats.free

import Free.{FlatMapped, Pure, Suspend}
import cats.{Foldable, Eval}

private[free] trait FreeFoldStep[S[_], A] {

def step: Free[S, A]

private type OnFlatMapped[X] = (S[X], X => Free[S, A])

/**
* A combination of step and fold. May be used to define interpreters with custom
* (non-monoidial) control flow.
*/
final def foldStep[B](
onPure: A => B,
onSuspend: S[A] => B,
onFlatMapped: [X] => (S[X], X => Free[S, A]) => B
): B =
this.step match {
case Pure(a) => onPure(a)
case Suspend(a) => onSuspend(a)
case FlatMapped(Suspend(fa), f) => onFlatMapped(fa, f)
case _ => sys.error("FlatMapped should be right associative after step")
}

final def foldLeft[B](fa: Free[S, A], b: B)(f: (B, A) => B)(implicit F: Foldable[S]): B =
fa.foldStep(
a => f(b, a),
fa => F.foldLeft(fa, b)(f),
[X] => (sx: S[X], g: X => Free[S, A]) => F.foldLeft(sx, b)((bb, x) => foldLeft(g(x), bb)(f))
)

final def foldRight[B](fa: Free[S, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B])(implicit F: Foldable[S]): Eval[B] =
fa.foldStep(
a => f(a, lb),
fa => F.foldRight(fa, lb)(f),
[X] => (sx: S[X], g: X => Free[S, A]) => F.foldRight(sx, lb)((a, lbb) => foldRight(g(a), lbb)(f))
)
}
30 changes: 3 additions & 27 deletions free/src/main/scala/cats/free/Free.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import cats.arrow.FunctionK
* using the heap instead of the stack, allowing tail-call
* elimination.
*/
sealed abstract class Free[S[_], A] extends Product with Serializable {
sealed abstract class Free[S[_], A] extends Product with Serializable with FreeFoldStep[S, A] {

import Free.{FlatMapped, Pure, Suspend}

Expand Down Expand Up @@ -73,22 +73,6 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
}
}

/**
* A combination of step and fold. May be used to define interpreters with custom
* (non-monoidial) control flow.
*/
final def foldStep[B](
onPure: A => B,
onSuspend: S[A] => B,
onFlatMapped: ((S[Any], Any => Free[S, A])) => B
): B =
this.step match {
case Pure(a) => onPure(a)
case Suspend(a) => onSuspend(a)
case FlatMapped(Suspend(fa), f) => onFlatMapped((fa.asInstanceOf[S[Any]], f.asInstanceOf[Any => Free[S, A]]))
case _ => sys.error("FlatMapped should be right associative after step")
}

/**
* Run to completion, using a function that extracts the resumption
* from its suspension functor.
Expand Down Expand Up @@ -315,18 +299,10 @@ private trait FreeFoldable[F[_]] extends Foldable[Free[F, *]] {
implicit def F: Foldable[F]

final override def foldLeft[A, B](fa: Free[F, A], b: B)(f: (B, A) => B): B =
fa.foldStep(
a => f(b, a),
fa => F.foldLeft(fa, b)(f),
{ case (fx, g) => F.foldLeft(fx, b)((bb, x) => foldLeft(g(x), bb)(f)) }
)
fa.foldLeft(fa, b)(f)

final override def foldRight[A, B](fa: Free[F, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
fa.foldStep(
a => f(a, lb),
fa => F.foldRight(fa, lb)(f),
{ case (fx, g) => F.foldRight(fx, lb)((a, lbb) => foldRight(g(a), lbb)(f)) }
)
fa.foldRight(fa, lb)(f)
}

private trait FreeTraverse[F[_]] extends Traverse[Free[F, *]] with FreeFoldable[F] {
Expand Down

0 comments on commit 8abdf3c

Please sign in to comment.