将多个JsResult与无形

时间:2016-09-14 13:31:14

标签: scala shapeless hlist

我正在寻找一种方法将多个JsResult组合成一个。 这是我第一次尝试不使用Shapeless

def combineJsResult[A,B](res1: JsResult[A], res2: JsResult[B]): JsResult[(A, B)] = (res1, res2) match {
    case (r1: JsError, r2: JsError) => r1 ++ r2
    case (JsSuccess(r1, _), JsSuccess(d, _)) => JsSuccess(r1 -> d)
    case (r1: JsError, _) => r1
    case (_, r2: JsError) => r2
  }

我想要的是一个带有n个JsResult的函数,并将它们组合成一个JsResult [(A,B,C,...)]。现在我知道scala关于抽象的限制了。 我尝试使用Shapeless多个代码,但由于JsResult是一个类型构造函数和方差问题,因此没有编译。 这是我脑海中的算法:

编写一个函数,将任意类型的JsResult的HList作为参数。 foldRight在列表中使用JsSuccess(HNil)作为初始元素,并将上述函数的变体(将结果类型更改为JsResult [HList])作为折叠函数。

这是我的最终代码(不编译)

import play.api.libs.json.{JsError, JsResult, JsSuccess}
import shapeless.{Generic, HList, HNil, Poly2}

object merger extends Poly2 {
  def apply = at{ (res1: JsResult[_], res2: JsResult[_]) => {
    (res1, res2) match {
      case (r1: JsError, r2: JsError) => r1 ++ r2
      case (JsSuccess(r1, _), JsSuccess(d, _)) => JsSuccess(r1 :: d :: HNil)
      case (r1: JsError, _) => r1
      case (_, r2: JsError) => r2
    }
  } }
}

def combineJsResults[P <: Product, L <: HList](p: P)(implicit gen: Generic.Aux[P, L]) = {
  gen.to(p).foldRight[JsResult[HList]](JsSuccess(HNil))(merger)
}

combineJsResults(JsSuccess(1), JsSuccess("2"), JsSuccess(true))

非常感谢您帮助我了解如何解决此问题。

编辑:我取得了一些进展

import play.api.libs.json.{JsError, JsSuccess}
import shapeless._

object combine extends Poly2 {
  def concatSuccess[L, R <: HList](l: JsSuccess[L], r: JsSuccess[R]): JsSuccess[L :: R] = JsSuccess(l.value :: r.value)

  implicit def successSuccess[L, R <: HList] = at[JsSuccess[L], JsSuccess[R]](concatSuccess)
  implicit def errorSuccess[R <: HList] = at[JsError, JsSuccess[R]]((l: JsError, r : JsSuccess[R]) => l)
  implicit val errorError = at[JsError, JsError](_ ++ _)
  implicit def successError[S] = at[JsSuccess[S], JsError]((l: JsSuccess[S], r: JsError) => r)
}

(JsSuccess(true) :: HNil).foldRight(JsSuccess(HNil))(combine)
(JsError("error") :: HNil).foldRight(JsSuccess(HNil))(combine)

val res1 = (JsSuccess(true) :: JsSuccess(1) :: HNil).foldRight(JsSuccess(HNil))(combine)
(JsError("error1") :: JsError("error2") :: HNil).foldRight(JsSuccess(HNil))(combine)
(JsSuccess(true) :: JsError("error2") :: HNil).foldRight(JsSuccess(HNil))(combine)

此代码编译,它成功地将JsResult [_]列表转换为JsResult [HList],现在我需要能够将该HList转换为元组以将其传递给案例类的tupled方法。 我查看了涉及使用Generic对象的示例,但它没有编译,因为Generic [some case class] .to方法需要一个Repr参数而不是HList。 有没有人有任何想法? 感谢

0 个答案:

没有答案