Scala: как преобразовать HList из ValidatedNel в ValidatedNel из HList

Я успешно использовал cats.data.Validated для решения приведенной ниже проблемы, но столкнулся с проблемой, используя мое существующее решение для класса case с более чем 22 членами (поскольку конструктор нельзя превратить в Function).

Вот моя цель: сгенерировать группу ValidatedNel[E, T], упорядочить их в ValidatedNel[E, (T1, T2, ...)], затем mapN(DAOClass) (где DAOClass — это case class с указанными аргументами). Это работает для менее чем 22 аргументов, но не работает с большим количеством аргументов из-за двух проблем:

  1. (T1, T2, ...) не может иметь более 22 компонентов
  2. DAOClass.apply нельзя преобразовать в Function

Поэтому я изучаю возможность использования shapeless.HList для обработки части 1 и имею проблемы. Я должен иметь возможность использовать Generic[DAOClass], чтобы удовлетворительно обрабатывать часть 2, когда я доберусь до нее, или, если это не сработает, используйте расширяемые записи с немного большим количеством шаблонов.

Вот небольшой пример кода (не с 22 компонентами):

package example

import cats.syntax.validated._
import cats.data.ValidatedNel
import cats.sequence._
import shapeless._

case class DAOClass(a: Int, b: Int)

object DAOClass {

  def generate: ValidatedNel[String, DAOClass] = {

    val hlist: ValidatedNel[String, Int] :: ValidatedNel[String, Int] :: HNil =
      1.validNel :: 2.validNel :: HNil

    val hlistSequence: ValidatedNel[String, Int :: Int :: HNil] = hlist.sequence

    hlistSequence.map(Generic[DAOClass].from)

  }

}

При этом используется библиотека kittens для последовательности файлов HList.

К сожалению, это дает мне ошибку компиляции:

[error] ...src/main/scala/example/DAOClass.scala:17:73: cannot construct sequencer, make sure that every item of your hlist shapeless.:: [cats.data.ValidatedNel[String,Int],shapeless.::[cats.data.ValidatedNel[String,Int],shapeless.HNil]] is an Apply
[error]     val hlistSequence: ValidatedNel[String, ::[Int, ::[Int, HNil]]] = hlist.sequence
[error]                                                                             ^

Я извлек это в тестовый проект; вот мой build.sbt:

lazy val root = (project in file(".")).
  settings(
    inThisBuild(List(
      organization := "com.example",
      scalaVersion := "2.12.6",
      version      := "0.1.0-SNAPSHOT"
    )),
    name := "shapeless-validation",
    resolvers ++= Seq(
      Resolver.sonatypeRepo("releases")
    ),
    libraryDependencies ++= Seq(
      "com.chuusai"   %% "shapeless" % "2.3.3",
      "org.scalatest" %% "scalatest" % "3.0.5" % "test",
      "org.typelevel" %% "cats-core" % "1.1.0",
      "org.typelevel" %% "kittens"   % "1.1.0"
    )
  )

Что мне не хватает? Нужно ли мне где-то импортировать больше имплицитов? Есть лучший способ это сделать?


person meustrus    schedule 12.07.2018    source источник


Ответы (1)


Вы забыли добавить

scalacOptions += "-Ypartial-unification"

до build.sbt. Для нормальной работы с cats это обычно обязательно.

Теперь

hlistSequence.map(Generic[DAOClass].from)

производит ValidatedNel[String, DAOClass]:

println(DAOClass.generate) // Valid(DAOClass(1,2))
person Dmytro Mitin    schedule 18.07.2018
comment
Идеальный! С scalacOptions += "-Ypartial-unification" в моем build.sbt эта DAO из 26 участников может быть сгенерирована из HList из ValidatedNel с! - person meustrus; 10.08.2018