2015-11-19 8 views
5

FreeはScalaz 7.1.5のモナドインスタンスではないので、ApplicativeApplyなどで定義されている便利なメソッドを使用することはできません。Scalaz 7.1.5のFreeはなぜMonadインスタンスではないのですか?

/* 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 

erorrメッセージは、

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 
      ^

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

また、何か不足していますか? (インポートなど)

答えて

6

これは、型エイリアスについて悩んでいるScalaコンパイラです。あなたには2つの選択肢があります(少なくとも2つの選択肢があります - おそらく他の合理的な回避策があります)。最初は、タイプエイリアスを少し違って分解します。

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

あなたがこの書き込み:この代わりに

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

そしてMonad[ResultSetIO]をうまくコンパイルします。あなたは|@|*>、およびreplicateMのために1つの余分のインポートが必要になります。

import scalaz.syntax.applicative._ 

他のオプションは、あなた自身をそのままFreeCを残し、モナドのインスタンスを定義することで、scalacはあなたのためにそれを見つけることができませんので、。幸いにも、あなたがもう少し簡単にあなたが提案としてそれを書くよりもこれを行うことができます。

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

を私が最初のアプローチを好むが、本当にあなたが選択した問題ではありません。

ここでは便宜上簡略化され、完全な作業例です:

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) 

これは7.1.5でちょうど罰金をコンパイルします。


完全を期すために、コンパイラは、私はちょうどドをしたFreeCバージョン(ロブ・ノリスは、このコードのresponsibleである、のためのインスタンスを見つけるのに役立ついくつかのUnapply機械を定義することである第三の方法は、あります-kind投影):

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 
} 

これは、あなたがモナドのインスタンスを毎回定義せずにFreeCを使用することができます。私はまだFreeCをあきらめて、Freeを使うのが良い考えです。

+1

ああ、もう1つ:4.アップアップSI-5075、指を挟んでさらに4〜5年待ってください... –

+0

詳細な説明や他の便利な機能をご利用いただきありがとうございます。私はScalaz 7.2.xに 'FreeC'がないので、最初の方法を選択したいと思います。 – 1ambda

関連する問題