Skip to content

Commit

Permalink
combine two functions to leverage compiler completencess checks in a …
Browse files Browse the repository at this point in the history
…case match
  • Loading branch information
svalaskevicius committed Nov 29, 2015
1 parent 75e07fb commit 9ffaade
Showing 1 changed file with 4 additions and 12 deletions.
16 changes: 4 additions & 12 deletions free/src/main/scala/cats/free/Free.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,31 +116,23 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
runM2(this)
}

/** Takes one evaluation step in the Free monad, re-associating left-nested binds in the process. */
@tailrec
final def step: Free[S, A] = this match {
case Gosub(Gosub(c, f), g) => c.flatMap(cc => f(cc).flatMap(g)).step
case Gosub(Pure(a), f) => f(a).step
case x => x
}

/**
* Catamorphism for `Free`.
*
* Run to completion, mapping the suspension with the given transformation at each step and
* accumulating into the monad `M`.
*/
@tailrec
final def foldMap[M[_]](f: S ~> M)(implicit M: Monad[M]): M[A] = {
step match {
final def foldMap[M[_]](f: S ~> M)(implicit M: Monad[M]): M[A] =
this match {
case Pure(a) => M.pure(a)
case Suspend(s) => f(s)
case Gosub(c, g) => c match {
case Suspend(s) => g(f(s)).foldMap(f)
case _ => throw new Error("Unexpected operation. The case should have been eliminated by `step`.")
case Gosub(cSub, h) => cSub.flatMap(cc => h(cc).flatMap(g)).foldMap(f)
case Pure(a) => g(a).foldMap(f)
}
}
}

/**
* Compile your Free into another language by changing the suspension functor
Expand Down

0 comments on commit 9ffaade

Please sign in to comment.