为什么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是一个更好的主意. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容