Why is Free not a monad instance in Scalaz 7.1.5?

Since Free not an instance of a monad in Scalaz 7.1.5, I cannot use the useful method defined in Applicative , Apply , etc.

 /* ref - http://tpolecat.imtqy.com/assets/sbtb-slides.pdf */ import Free._, Coyoneda._ type ResultSetIO[A] = FreeC[ResultSetOp, A] val next : ResultSetIO[Boolean] = liftFC(Next) def getString(index: Int): ResultSetIO[String] = liftFC(GetString(index)) def getInt(index: Int) : ResultSetIO[Int] = liftFC(GetInt(index)) def close : ResultSetIO[Unit] = liftFC(Close) // compile errors def getPerson1: ResultSetIO[Person] = (getString(1) |@| getInt(2)) { Person(_, _)} def getNextPerson: ResultSetIO[Person] = next *> getPerson def getPeople(n: Int): ResultSetIO[List[Person]] = getNextPerson.replicateM(n) // List.fill(n)(getNextPerson).sequence 

erorr message,

 Error:(88, 19) value |@| is not a member of free.JDBC.ResultSetIO[String] (getString(1) |@| getInt(2)) { Person(_, _)} ^ Error:(91, 10) value *> is not a member of free.JDBC.ResultSetIO[Boolean] next *> getPerson ^ Error:(94, 19) value replicateM is not a member of free.JDBC.ResultSetIO[free.Person] getNextPerson.replicateM(n) // List.fill(n)(getNextPerson).sequence ^ 

Should I implement a monad instance for Free ?

 implicit val resultSetIOMonadInstance = new Monad[ResultSetIO] { override def bind[A, B](fa: ResultSetIO[A])(f: (A) => ResultSetIO[B]): ResultSetIO[B] = fa.flatMap(f) override def point[A](a: => A): ResultSetIO[A] = Free.point[CoyonedaF[ResultSetOp]#A, A](a) } 

Or am I missing something? (e.g. import)

+5
source share
1 answer

It's just a Scala compiler, fussy about type aliases. You have two options (or at least two options - there are probably other reasonable workarounds). The first is to break the type alias a little differently. Instead of this:

 type ResultSetIO[A] = FreeC[ResultSetOp, A] 

You write this:

 type CoyonedaResultSetOp[A] = Coyoneda[ResultSetOp, A] type ResultSetIO[A] = Free[CoyonedaResultSetOp, A] 

And then Monad[ResultSetIO] will compile just fine. You will need one additional import for |@| , *> and replicateM :

 import scalaz.syntax.applicative._ 

Another option is to leave FreeC as it is and determine the monad instance yourself, since scalac will not find it for you. Fortunately, you can make it a little easier than writing it as you suggest:

 implicit val monadResultSetIO: Monad[ResultSetIO] = Free.freeMonad[({ type L[x] = Coyoneda[ResultSetOp, x] })#L] 

I prefer the first approach, but it really doesn’t matter what you choose.

The full working example is simplified here for convenience:

 sealed trait ResultSetOp[A] case object Next extends ResultSetOp[Boolean] case class GetString(index: Int) extends ResultSetOp[String] case class GetInt(index: Int) extends ResultSetOp[Int] case object Close extends ResultSetOp[Unit] import scalaz.{ Free, Coyoneda, Monad } import scalaz.syntax.applicative._ type CoyonedaResultSetOp[A] = Coyoneda[ResultSetOp, A] type ResultSetIO[A] = Free[CoyonedaResultSetOp, A] val next: ResultSetIO[Boolean] = Free.liftFC(Next) def getString(index: Int): ResultSetIO[String] = Free.liftFC(GetString(index)) def getInt(index: Int): ResultSetIO[Int] = Free.liftFC(GetInt(index)) def close: ResultSetIO[Unit] = Free.liftFC(Close) case class Person(s: String, i: Int) def getPerson: ResultSetIO[Person] = (getString(1) |@| getInt(2))(Person(_, _)) def getNextPerson: ResultSetIO[Person] = next *> getPerson def getPeople(n: Int): ResultSetIO[List[Person]] = getNextPerson.replicateM(n) 

This will be perfectly compiled with 7.1.5.


For completeness, there is a third way: define some Unapply mechanisms to help the compiler find instances for the FreeC version (Rob Norris is responsible for this code I just tried):

 implicit def freeMonadC[FT[_[_], _], F[_]](implicit ev: Functor[({ type L[x] = FT[F, x] })#L] ) = Free.freeMonad[({ type L[x] = FT[F, x] })#L] implicit def unapplyMMFA[TC[_[_]], M0[_[_], _], M1[_[_], _], F0[_], A0](implicit TC0: TC[({ type L[x] = M0[({ type L[x] = M1[F0, x] })#L, x] })#L] ): Unapply[TC, M0[({ type L[x] = M1[F0, x] })#L, A0]] { type M[X] = M0[({ type L[x] = M1[F0, x] })#L, X] type A = A0 } = new Unapply[TC, M0[({ type L[x] = M1[F0, x] })#L, A0]] { type M[X] = M0[({ type L[x] = M1[F0, x] })#L, X] type A = A0 def TC = TC0 def leibniz = Leibniz.refl } 

This allows you to use FreeC without specifying monad instances each time. I still think that just giving up FreeC and using Free is the best idea.

+6
source

Source: https://habr.com/ru/post/1236275/


All Articles