(Re)Introduce[1] Free-er monads in Bow. Program allows you to get a monad from any type constructor. Unlike Free, it doesn't require F to be a functor, so not only does it defer the evaluation of flatMap calls for later interpretation into another monad, but also (unlike Free) defers calls to map.
Do we need both Free and Program?
Yes. When you use Free, certain properties can be enforced in the Functor implementation of F, meaning that those properties will be fulfilled no matter what interpreter you use later [2].
When you use Program, you cannot enforce properties on the Functor implementation of F, because it's just not a functor. But, on the other hand, you don't have to implement the Functor instance. So Program is easier to use, but you cannot guarantee custom properties hold. Context will tell what option is best for you.
Implementation details
Program is just Free<Coyoneda<F>>. Free needs a functor, since F is not a functor, we use Coyoneda<F> which is the free functor of F and defers evaluation of map. So, at the end, Program defers the evaluation of flatMap calls for later interpretation into another monad, but unlike Free, it also defers calls to map (thanks to the inner Coyoneda).
Testing details
I used the same test program found in the Free tests, but you can see how it is not a functor here!
Name
I'm not really happy with the name Program. I took it from Haskell, but it doesn't really tell what this type is about IMHO.
On the other hand, Freer is too similar to Free and I think this can cause confusion or problems in code.
A third option would be to come up with a new name that tries to capture the essence of this data type but is not similar to Free. Something like EvenFreer? But then it would be more difficult to relate this type to its Haskell and Scala counterpart.
Goal
(Re)Introduce[1] Free-er monads in Bow.
Program
allows you to get a monad from any type constructor. UnlikeFree
, it doesn't requireF
to be a functor, so not only does it defer the evaluation offlatMap
calls for later interpretation into another monad, but also (unlike Free) defers calls tomap
.Reference: free-operational
Do we need both
Free
andProgram
? Yes. When you useFree
, certain properties can be enforced in the Functor implementation ofF
, meaning that those properties will be fulfilled no matter what interpreter you use later [2].When you use
Program
, you cannot enforce properties on the Functor implementation of F, because it's just not a functor. But, on the other hand, you don't have to implement the Functor instance. SoProgram
is easier to use, but you cannot guarantee custom properties hold. Context will tell what option is best for you.Implementation details
Program
is justFree<Coyoneda<F>>
.Free
needs a functor, sinceF
is not a functor, we useCoyoneda<F>
which is the free functor ofF
and defers evaluation ofmap
. So, at the end,Program
defers the evaluation offlatMap
calls for later interpretation into another monad, but unlikeFree
, it also defers calls tomap
(thanks to the innerCoyoneda
).Testing details
I used the same test program found in the
Free
tests, but you can see how it is not a functor here!Name
I'm not really happy with the name Program. I took it from Haskell, but it doesn't really tell what this type is about IMHO.
On the other hand, Freer is too similar to
Free
and I think this can cause confusion or problems in code.A third option would be to come up with a new name that tries to capture the essence of this data type but is not similar to
Free
. Something likeEvenFreer
? But then it would be more difficult to relate this type to its Haskell and Scala counterpart.What's your view on the naming issue?
Notes
[1] The previous interpretation of Free was actually the Free-er monad! So we are just bringing it back. [2] See Purify code using free monads (Proofs section) for an example.