代码之家  ›  专栏  ›  技术社区  ›  Synesso

绕过状态中的不变结果类型

  •  3
  • Synesso  · 技术社区  · 7 年前

    State 这建立了一个具体的特征子类型,如 decodeFoo

    sealed trait Foo
    case class Bar(s: String) extends Foo
    case class Baz(i: Int) extends Foo
    
    val int: State[Seq[Byte], Int] = State[Seq[Byte], Int] {
      case bs if bs.length >= 4 =>
        bs.drop(4) -> ByteBuffer.wrap(bs.take(4).toArray).getInt
      case _ => sys.error(s"Insufficient data remains to parse int")
    }
    
    def bytes(len: Int): State[Seq[Byte], Seq[Byte]] = State[Seq[Byte], Seq[Byte]] {
      case bs if bs.length >= len => bs.drop(len) -> bs.take(len)
      case _ => sys.error(s"Insufficient data remains to parse $len bytes")
    }
    
    val bytes: State[Seq[Byte], Seq[Byte]] = for {
      len <- int
      bs <- bytes(len)
    } yield bs
    
    val string: State[Seq[Byte], String] = bytes.map(_.toArray).map(new String(_, Charset.forName("UTF-8")))
    
    val decodeBar: State[Seq[Byte], Bar] = string.map(Bar)
    val decodeBaz: State[Seq[Byte], Baz] = int.map(Baz)
    
    val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
      case 0 => decodeBar
      case 1 => decodeBaz
    }
    

    这将不会编译为 陈述 在猫中定义为 type State[S, A]

    Error:(36, 15) type mismatch;
     found   : cats.data.State[Seq[Byte],FooBarBaz.this.Bar]
        (which expands to)  cats.data.IndexedStateT[cats.Eval,Seq[Byte],Seq[Byte],FooBarBaz.this.Bar]
     required: cats.data.IndexedStateT[cats.Eval,Seq[Byte],Seq[Byte],FooBarBaz.this.Foo]
    Note: FooBarBaz.this.Bar <: FooBarBaz.this.Foo, but class IndexedStateT is invariant in type A.
    You may wish to define A as +A instead. (SLS 4.5)
        case 0 => decodeBar
    

    我可以通过扩大定义来解决这个问题 decodeBar decodeBaz 类型 State[Seq[Byte], Foo] . 这是前进的最佳途径吗?或者我可以采取不同的方法来避免扩大这些类型?

    1 回复  |  直到 7 年前
        1
  •  4
  •   Andrey Tyukin    7 年前

    Functor.widen 我们应该做到这一点。完整的可编译示例(带投影仪):

    import cats.data.State
    import cats.Functor
    
    object FunctorWidenExample {
      locally {
        sealed trait A
        case class B() extends A
    
        val s: State[Unit, B] = State.pure(new B())
        val t: State[Unit, A] = Functor[State[Unit, ?]].widen[B, A](s)
      }
    }
    

    在您的情况下,它将类似于:

    val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
      case 0 => Functor[State[Seq[Byte], ?]].widen[Bar, Foo](decodeBar)
      case 1 => Functor[State[Seq[Byte], ?]].widen[Bar, Foo](decodeBaz)
    }
    

    (其实没有必要,只是为了演示可能不太为人所知的语法):

    • 显式类型归属:

      val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
        case 0 => decodeBar.map(x => (x: Foo))
        case 1 => decodeBaz.map(x => (x: Foo))
      }
      
    • 使用 <:< apply

      val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
        case 0 => decodeBar.map(implicitly: Bar <:< Foo)
        case 1 => decodeBaz.map(implicitly: Baz <:< Foo)
      }