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

.

+3


source to share


1 answer


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)

      

+9


source







All Articles