【问题标题】:Avoid diverging implicit expansion on recursive MTL class避免递归 MTL 类的发散隐式扩展
【发布时间】:2018-06-15 23:14:11
【问题描述】:

我正在尝试使用 Hlist 在猫 mtl 中创建可组合的状态类型,并定义了 MonadState 如下

implicit def hlistStateMonad[M[_], S <: HList, S2]
(implicit S:Selector[S, S2], R:Replacer[S, S2, S2], M:MonadState[M, S]):MonadState[M, S2]

但是,即使S2 不是 HList,并且 Selector 和 Replacer 无法解析,它也不会在cats.mtl 中查找隐式 arg

我尝试定义 S2 <: hlist>

可测试代码如下:

object Test {
  implicit def hlistStateMonad[M[_], S <: HList, S2](implicit S:Selector[S, S2], R:Replacer[S, S2, S2], M:MonadState[M, S]):MonadState[M, S2] =
    new MonadState[M, S2] {

      val monad: Monad[M] = M.monad

      def inspect[A](f: S2 => A):M[A] =
        M.inspect(s => f(S(s)))

      def modify(f: S2 => S2):M[Unit] =
        M.modify(s => R(s, f(S(s))).asInstanceOf[(S2, S)]._2)

      def get:M[S2] =
        M.inspect(S.apply)

      def set(s2: S2): M[Unit] =
        M.modify(s => R(s, s2).asInstanceOf[(S2, S)]._2)
    }
}

  test("Monad state resolution with HList") {

    type M[V] = State[Int :: String :: HNil, V]

    import cats.mtl.instances.all._
    import Test._

    val m = implicitly[MonadState[M, Int]]
  }

【问题讨论】:

    标签: scala shapeless scala-cats


    【解决方案1】:

    添加查找 S2 不是 HList 的证据(如您所建议的那样)并在 Selector & Replacer 似乎为我解决问题之前查找 MonadState。

    怀疑它可能与编译器没有将 S 绑定到任何东西有关——只知道它的上限是 HList。 (但这是我最好的猜测)

    希望这会有所帮助。

    import cats.Monad
    import cats.data.State
    import cats.mtl.MonadState
    import org.scalatest.{FlatSpec, Matchers}
    import shapeless._
    import shapeless.::
    import shapeless.ops.hlist.{Replacer, Selector}
    import cats.mtl.instances.all._
    
    class Test extends FlatSpec with Matchers {
    
      implicit def hlistStateMonad[M[_], S <: HList, S2](
          implicit
          nEv: S2 <:!< HList,
          M: MonadState[M, S],
          S: Selector[S, S2],
          R: Replacer[S, S2, S2]): MonadState[M, S2] =
        new MonadState[M, S2] {
    
          val monad: Monad[M] = M.monad
    
          def inspect[A](f: S2 => A): M[A] =
            M.inspect(s => f(S(s)))
    
          def modify(f: S2 => S2): M[Unit] =
            M.modify(s => R(s, f(S(s))).asInstanceOf[(S2, S)]._2)
    
          def get: M[S2] =
            M.inspect(S.apply)
    
          def set(s2: S2): M[Unit] =
            M.modify(s => R(s, s2).asInstanceOf[(S2, S)]._2)
        }
    
      "Monad state resolution with HList" should "compile and maybe even run?" in {
    
        type M[V] = State[Int :: String :: HNil, V]
    
        val m = implicitly[MonadState[M, Int]]
    
        val res = for {
          a <- m.set(5)
          b <- m.get
        } yield b + 1
    
        res.run(1 :: "test" :: HNil).value._2 shouldBe 6
      }
    }
    

    【讨论】:

      【解决方案2】:

      试试

      import cats.Monad
      import cats.data.State
      import cats.mtl.MonadState
      import shapeless.{::, HList, HNil, Lazy}
      import shapeless.ops.hlist.{Replacer, Selector}
      
      import scala.language.higherKinds
      
      object Test {
        implicit def hlistStateMonad[M[_], S <: HList, S2](implicit S:Selector[S, S2], R:Replacer[S, S2, S2], M:Lazy[MonadState[M, S]]):MonadState[M, S2] =
      new MonadState[M, S2] {
      
          val monad: Monad[M] = M.value.monad
      
          def inspect[A](f: S2 => A):M[A] =
          M.value.inspect(s => f(S(s)))
      
          def modify(f: S2 => S2):M[Unit] =
          M.value.modify(s => R(s, f(S(s))).asInstanceOf[(S2, S)]._2)
      
          def get:M[S2] =
          M.value.inspect(S.apply)
      
          def set(s2: S2): M[Unit] =
          M.value.modify(s => R(s, s2).asInstanceOf[(S2, S)]._2)
        }
      }
      

      至少错误发生了变化。

      【讨论】:

        猜你喜欢
        • 2017-12-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-01
        • 2011-06-20
        • 1970-01-01
        相关资源
        最近更新 更多