The translation of this Haskell code into Scala will be
sealed abstract class Free[S[_], A] case class Return[S[_], A](a: A) extends Free[S, A] case class Suspend[S[_], A](a: S[Free[S, A]]) extends Free[S, A]
The Haskell implementation does not need a Gosub case thanks to a lazy evaluation. This view will work in Scala, but it will lead to problems with stack overflow due to (strict assessment and) lack of elimination of the tail call. To make it stack-safe, we introduce flatMap lazily since Gosub (I think flatMap would be a better name):
case class Gosub[S[_], B, C](a: Free[S, C], f: C => Free[S, B]) extends Free[S, B]
As a bonus, introducing Gosub simplifies Suspend to
case class Suspend[S[_], A](a: S[A]) extends Free[S, A]
because we don’t need to do flatMap by matching the contents of S[_] anymore - we present flatMap explicitly as Gosub s.
As a result, this resulting view, unlike the Haskell view, allows us to do everything we need to do with Free , without requiring Functor[S] . Therefore, we don’t even need to bother with the Coyoneda trick when our S not a Functor .
Tomas mikula
source share