I have the following classes:
class Person(id: Long, name: String)
sealed class PersonError {
data class InvalidId(val field: String) : PersonError()
data class InvalidName(val field: String) : PersonError()
}
As I loop and validate through multiple persons, I get:
List<ValidatedNel<Error, Person>>
or:
List<Validated<Error, Person>>
How do I transform the above list to:
Validated<Nel<MappingError>, List<Person>>
I want to accumulate all errors related to the validation of all persons. This is needed, because I want to do the following:
val vId : ValidatedNel<Error, Long> = validateId(id).toValidatedNel()
val vPersons : List<ValidatedNel<Error, Person>> = validatePersons(persons).toValidatedNel()
ValidatedNel.applicative<Nel<PersonError>>(Nel.semigroup<PersonError>())
.map(vId, vPersons) {
val id = it.a
val persons = it.b
Group(id, persons)
}.fix()
The current 'map' does not accept a List<ValidatedNel<Error>, Person>>
The left side of Validated
requires a Semigroup
to collect all errors; the right side of your Validated
requires a product
(since Group(a, b)
is a product type); and the accumulation of errors within a specific person requires a sequence
(or traverse
with identity function) to collect all errors for a given person, so the following should work:
val SE = Nel.semigroup<PersonError>()
val validatedGroup: ValidatedNel<PersonError, Group> = vId.product(
SE,
vPersons.sequence(ValidatedNel.applicative(SE)).fix().map { it.fix() }
).map(::Group.tupled2())
I think in an upcoming release of Arrow the calls to fix() will be minimized or eliminated, so hopefully .fix().map { it.fix() }
can be removed soon.