0

为什么我需要在第一行添加类型注释? c.get[List[String]]("primary-group")Decoder.Result[List[String]]flatMap它应该保持顶级类型之后,Decoder.Result[String]但它会更改为 Either[DecodingFailure, String]。为什么?是它的问题dependent type吗?

  case class JWTPayload(primaryGroup: Group, groupMember: List[Group], name: String, pid: String)

  implicit val jwtPayloadDecoder: Decoder[JWTPayload] = Decoder.instance(c =>
    (
      c.get[List[String]]("primary-group").flatMap(l => if(l.size == 1) l.head.asRight else DecodingFailure("", c.history).asLeft) : Decoder.Result[String],
      c.get[List[String]]("group-member"),
      c.get[String]("name"),
      c.get[String]("pid")
    ).map4(
     JWTPayload
    )
  )

没有: Decoder.Result[String我得到

Error:(43, 7) value map4 is not a member of (scala.util.Either[io.circe.DecodingFailure,String], io.circe.Decoder.Result[List[String]], io.circe.Decoder.Result[String], io.circe.Decoder.Result[String])
possible cause: maybe a semicolon is missing before `value map4'?
    ).map4(

谢谢

4

1 回答 1

2

这不是一个完整的答案,但我希望它能提供一些见解。这里的关键部分是如何map4实现。从猫 0.9 开始,它是通过cats.syntax.TupleCartesianSyntaxtrait 完成的,它的隐式catsSyntaxTuple4Cartesian将 4 元组包装到一个cats.syntax.Tuple4CartesianOps类中(在猫 1.0 中,“笛卡尔”更改为“半群”)。此代码由Boilerplate.scala为所有最多 22 个元组自动生成。自动生成的代码如下所示:

implicit def catsSyntaxTuple4Cartesian[F[_], A0, A1, A2, A3](t4: Tuple4[F[A0], F[A1], F[A2], F[A3]]): Tuple4CartesianOps[F, A0, A1, A2, A3] = new Tuple4CartesianOps(t4)


private[syntax] final class Tuple4CartesianOps[F[_], A0, A1, A2, A3](t4: Tuple4[F[A0], F[A1], F[A2], F[A3]]) {
  def map4[Z](f: (A0, A1, A2, A3) => Z)(implicit functor: Functor[F], cartesian: Cartesian[F]): F[Z] = Cartesian.map4(t4._1, t4._2, t4._3, t4._4)(f)
  def contramap4[Z](f: Z => (A0, A1, A2, A3))(implicit contravariant: Contravariant[F], cartesian: Cartesian[F]): F[Z] = Cartesian.contramap4(t4._1, t4._2, t4._3, t4._4)(f)
  def imap4[Z](f: (A0, A1, A2, A3) => Z)(g: Z => (A0, A1, A2, A3))(implicit invariant: Invariant[F], cartesian: Cartesian[F]): F[Z] = Cartesian.imap4(t4._1, t4._2, t4._3, t4._4)(f)(g)
  def apWith[Z](f: F[(A0, A1, A2, A3) => Z])(implicit apply: Apply[F]): F[Z] = apply.ap4(f)(t4._1, t4._2, t4._3, t4._4)
}

注意F[_](functor) 类型参数。实际上,此代码将map4方法添加到任何 4 元组,其中每个内部类型在某些类型上是相同的函子。

因此,假设您这样做了import cats.implicits._,在(部分)隐式解析之后,您的代码实际上是这样的:

cats.implicits.catsSyntaxTuple4Cartesian[Decoder.Result, String, List[String], String, String](
  c.get[List[String]]("primary-group").flatMap(l => if (l.size == 1) l.head.asRight else DecodingFailure("", c.history).asLeft): Decoder.Result[String],
  c.get[List[String]]("group-member"),
  c.get[String]("name"),
  c.get[String]("pid")
).map4[JWTPayload](
  JWTPayload
)

如果您不指定Decoder.Result[String],Scala 编译器不够聪明,无法将其拆分Either[DecodingFailure, String]为仿函数类型Either[DecodingFailure, _]String然后

  1. 会有匹配FunctorCartesian隐含的对象(实际上是由cats.implicits对象通过cats.instances.AllInstancescats.instances.EitherInstances特征提供的)

  2. 它将匹配用于元组中其他 3 个字段的函子类型(即Decoder.Result[_])。

所以我认为这种行为是map4通过隐式 Ops 类添加到 4 元组的事实和底层类型Either是 2 位泛型类型而不是简单的Functor.

于 2017-11-23T22:09:25.200 回答