1

複数の 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 引数を想定しているため、コンパイルされません。誰にもアイデアはありますか?ありがとう

4

0 に答える 0