2015-11-19 8 views
5

Da Free in Scalaz 7.1.5 keine Monad-Instanz ist, kann ich keine sinnvolle Methode verwenden, die in Applicative, Apply usw. definiert ist.Warum ist Free nicht Monad Instanz in Scalaz 7.1.5?

/* ref - http://tpolecat.github.io/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 

die erorr Nachricht ist,

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 
      ^

Soll ich für Free Monade Instanz implementieren?

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) 
} 

Oder fehlt mir etwas? (z. B. Import)

Antwort

6

Dies ist nur der Scala-Compiler, der sich mit Typaliasen beschäftigt. Sie haben zwei Möglichkeiten (oder mindestens zwei Optionen - es gibt wahrscheinlich andere sinnvolle Problemumgehungen). Die erste besteht darin, den Typ-Alias ​​etwas anders zu gliedern. Statt dessen:

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

Sie schreiben dies:

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

Und dann wird Monad[ResultSetIO] kompilieren gut. Sie werden einen zusätzlichen Import benötigen für |@|, *> und replicateM:

import scalaz.syntax.applicative._ 

Die andere Möglichkeit, die FreeC zu verlassen, wie es ist und definieren die Monade Instanz selbst, da scalac es nicht für Sie finden. Zum Glück können Sie diese ein wenig mehr tun, einfach, als es aus, wie Sie schreiben schlagen:

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

ich den ersten Ansatz bevorzugen, aber es ist nicht wirklich wichtig, was Sie wählen.

Hier ist ein vereinfachtes komplettes Arbeitsbeispiel aus Gründen der Bequemlichkeit:

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) 

Die mit 7.1.5 nur übersetzt werden kann.


Aus Gründen der Vollständigkeit, gibt es eine dritte Möglichkeit ist, die einige Unapply Maschinen zu definieren, ist der Compiler-Instanzen für die FreeC Version (Rob Norris ist responsible für diesen Code für Sie zu finden, die ich gerade de habe -kind projiziert):

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 
} 

Diese Sie FreeC verwenden können, ohne jedes Mal Monade Instanzen zu definieren. Ich denke immer noch, dass es einfach besser ist, auf FreeC zu verzichten und Free zu verwenden.

+1

Oh, und noch eins: 4. Upvote SI-5075, drücken Sie die Daumen, und warten Sie weitere vier oder fünf Jahre ... –

+0

Vielen Dank für die ausführliche Erklärung und nützliche andere Alternativen. Ich möchte den ersten Weg wählen, da Scalaz 7.2.x kein 'FreeC' hat. – 1ambda