Using Free with a non-functor in Scalaz
In the book "FP in Scala", this approach is for using ADT S
as an abstract set of commands, for example
sealed trait Console[_]
case class PrintLine(msg: String) extends Console[Unit]
case object ReadLine extends Console[String]
and composing them with the help Free[S, A]
, where it S
will later be translated into the IO monad. Can this be done with a Scalaz Free
type? It seems that all methods run
require a functor instance for S
.
source to share
yes, you need a functor, but you can create it with Coyoneda
.
Coyoneda
turns any F[A]
into Coyoneda[F,A]
, and Coyoneda[F,A]
is a functor.
scala> type ConsoleCoyo[A] = Coyoneda[Console, A]
defined type alias ConsoleCoyo
Then scalaz Free has a type alias just for that:
/** A free monad over the free functor generated by `S` */
type FreeC[S[_], A] = Free[({type f[x] = Coyoneda[S, x]})#f, A]
So now we have a free monad for the console:
scala> type ConsoleMonad[A] = Free.FreeC[ConsoleCoyo,A]
defined type alias ConsoleMonad
you will also find it handy that scalaz Free has a function to raise F [A] right into the monad:
/** A free monad over a free functor of `S`. */
def liftFC[S[_], A](s: S[A]): FreeC[S, A] =
liftFU(Coyoneda lift s)
for example:
scala> Free.liftFC(ReadLine)
res1: scalaz.Free.FreeC[Console,String] = Suspend(scalaz.Coyoneda$$anon$22@360bb132)
source to share