複数の JsResult を 1 つに結合する方法を探しています。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 が型コンストラクターであり、差異の問題であるため、コンパイルできませんでした。私が考えているアルゴリズムは次のとおりです。
Any 型の JsResult の HList を引数とする関数を書く。初期要素として JsSuccess(HNil) を使用し、折りたたみ関数として上記の関数のバリエーション (結果の型を JsResult[HList] に変更) を使用して、リストの foldRight を作成します。
これが私の最終的なコードです(コンパイルしていません)
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 をタプルに変換して、ケース クラスのタプル メソッドに渡す必要があります。Generic オブジェクトの使用に関する例を見ましたが、Generic[some case class].to メソッドが HList の代わりに Repr 引数を想定しているため、コンパイルされません。誰にもアイデアはありますか?ありがとう