Я начал с чего-то вроде этого:
def nonEmpty[A] = (msg: String) => (a: Option[A]) => a.toSuccess(msg)
val postal: Option[String] = request.param("postal")
val country: Option[String] = request.param("country")
val params =
(postal |> nonEmpty[String]("no postal" )).toValidationNel |@|
(country |> nonEmpty[String]("no country")).toValidationNel
params { (postal, country) => ... }
Теперь я подумал, что было бы неплохо уменьшить шаблон для лучшей читабельности и чтобы не объяснять младшим членам команды, что означают .toValidateNel
и |@|
. Первой мыслью было List
, но потом последняя строка перестала работать, и мне пришлось отказаться от некоторой статической безопасности. Поэтому я посмотрел в сторону Shapeless:
import shapeless._; import poly._; import syntax.std.tuple._
val params = (
postal |> nonEmpty[String]("no postal"),
country |> nonEmpty[String]("no country")
)
params.map(_.toValidatioNel).reduce(_ |@| _)
однако я даже не могу пройти мимо бита .map(...)
. Я пробовал в соответствии с предложением #scalaz:
type Va[+A] = Validation[String, A]
type VaNel[+A] = ValidationNel[String, A]
params.map(new (Va ~> VaNel) { def apply[T](x: Va[T]) = x.toValidationNel })
...но безрезультатно.
Я обратился за помощью к #scalaz, но, похоже, у людей нет готового ответа. Тем не менее, я действительно заинтересован в том, чтобы узнать, как решить эту проблему как в практических, так и в учебных целях.
P.S. на самом деле мои проверки заключены в Kleisli[Va, A, B]
, чтобы я мог составлять отдельные шаги проверки, используя >=>
, но это кажется ортогональным к проблеме, поскольку к тому времени, когда будет достигнуто .map(...)
, все Kleisli
s будут "сокращены" до Validation[String, A]
.
Poly1
как объект (по разным дурацким причинам, связанным со Scala, связанным со стабильными идентификаторами). Это очень похоже на обход, иtraverse
от shapeless-contrib позволит вам выполнитьtoValidationNel
и (моральный эквивалент)reduce(_ |@| _)
за один шаг. - person Travis Brown   schedule 16.10.2014