加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

为什么Free不是Scalaz 7.1.5中的monad实例?

发布时间:2020-12-16 09:55:29 所属栏目:安全 来源:网络整理
导读:由于Free不是 Scalaz 7.1.5中的monad实例,因此我无法使用Applicative,Apply等中定义的有用方法. /* ref - http://tpolecat.github.io/assets/sbtb-slides.pdf */import Free._,Coyoneda._type ResultSetIO[A] = FreeC[ResultSetOp,A]val next : ResultSetIO[
由于Free不是 Scalaz 7.1.5中的monad实例,因此我无法使用Applicative,Apply等中定义的有用方法.

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

我应该免费实现monad实例吗?

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

或者,我错过了什么? (例如进口)

解决方法

这只是Scala编译器对类型别名的挑剔.您有两个选择(或至少两个选择 – 可能还有其他合理的解决方法).第一种是略微区分类型别名.而不是这个:

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

你写这个:

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

然后Monad [ResultSetIO]将编译得很好.您需要为| @ |,*>和replicateM添加一个额外的导入:

import scalaz.syntax.applicative._

另一个选择是保持FreeC不变并自己定义monad实例,因为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]

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编译得很好.

为了完整起见,还有第三种方法,即定义一些Unapply机制来帮助编译器找到FreeC版本的实例(Rob Norris对于这个代码来说是responsible,我刚刚对它进行了类型预测):

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,A0]] {
  type M[X] = M0[({ type L[x] = M1[F0,X]
  type A = A0
} = new Unapply[TC,X]
  type A = A0
  def TC = TC0
  def leibniz = Leibniz.refl
}

这允许您在不使用每次定义monad实例的情况下使用FreeC.我仍然认为放弃FreeC并使用Free是一个更好的主意.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读