Lev Denisov
Lev Denisov

Reputation: 2171

Scala fs2: what fromFreeC and Algebra do?

When I go into the implementation of fs2 stream operations I often see fromFreeC and Algebra used there.

What exactly fromFreeC and Algebra do? Why and when one needs them?

Here is an example, an fs2 stream operation eval which evaluates effects and returns an effectful stream.

def eval[F[_], O](fo: F[O]): Stream[F, O] =
   fromFreeC(Algebra.eval(fo).flatMap(Algebra.output1))

Upvotes: 1

Views: 136

Answers (1)

Diego Alonso
Diego Alonso

Reputation: 761

In the source code for version 2.1.0, classes Pull, Stream, and FreeC were defined as follows:

class FreeC[F[_], +O, +R]
class Pull[+F[_], +O, +R](free: FreeC[Nothing, O, R]) 
class Stream[+F[_], +O](free: FreeC[Nothing, O, Unit])

The key problem is that Stream and Pull were covariant on the F[_] parameter, whereas FreeC is invariant. As a consequence, you cannot apply the F parameter of Stream or Pull directly to the FreeC type of the wrapped value. To bridge that, we used Nothing as argument for FreeC in those free fields, and apply use asInstanceOf conversions between a FreeC[Nothing, O, Unit] to a FreeC[F O, Unit], and back again.

However, in this Pull Request we made the class FreeC covariant on F[_], just like Stream and Pull, so we could just define:

class FreeC[+F[_], +O, +R]
class Pull[+F[_], +O, +R] (free: FreeC[F, O, R])
class Stream[+F[_], +O] (free: FreeC[F O, Unit])

Thus, the fromFreeC function was dropped. This was included in release 2.2.0.


The use of Nothing makes use of a Scala-2 type system feature: both Any and Nothing are polykinded types, so they can be applied as arguments for type parameters of the form A, F[_], A[_[_]], etc.

Upvotes: 1

Related Questions