Reputation: 2171
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
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