how to use `Either` and `Validated` together? `Eit...
# arrow
m
how to use
Either
and
Validated
together?
Either
for fetching and
Validated
for validating data. I have code that parses some data and then I need to perform some check on that data to determine is it valid or not. parsing function return
Either
because parsing can fail and I want to validation function to return
Validated
based on validation logic
s
something like this should work:
Copy code
fun fetchData(): Either<Error, Success> = TODO()

fun validateData(s: Success): ValidatedNel<Error, ValidData> = TODO()

fun fetchAndValidate(): Either<Error, ValidData> = 
    fetchData.flatMap { success ->
        validateData(success).toEither()
    }
note: if fetching from network/db you also might wanna do
fetchData
as
suspend
you can also use
either {}
block instead of
flatMap
note: the error sides on both functions must match (have the same supertype)
m
thank you. what if I need different error types? one for fetch error other for validation error? @stojan
😉 1
s
you can convert from one to the other using
mapLeft
m
I forgot about that 😄, thanks
s
or have some sealed class:
Copy code
sealed class MyErrors {
    object ParseErrors : MyErrors()
    object ValidationError : MyErrors()
}
using object because I'm lazy.... you would typically have more data
👍 2
m
@stojan this is not working for me. in
fold
at the end of the chain error is
Any
s
can you share some code?
I'm guessing you have different errors in the Either/Validated, so the only common parent is
Any
m
I did and that wasn’t the problem, now I need that error so I used same type for error, still
Any
changed it to
Throwable
still nothing
s
would be great if you could share a minimal example that shows the problem
m
Copy code
fun List<String>.parseData(): Either<Throwable, List<Data>> = TODO()

fun List<Data>.validate(): ValidatedNel<Throwable, List<Data>> = TODO()

fun main() {
    readData()
        .flatMap(List<String>::parseData)
        .flatMap { data -> data.validate().toEither() }
        .fold(
            { /// it is Any },
            {},
        )
if there a way to use different error and still get it recognise types? and is there a reason why I should not do that?
and when I have just
parseData
it still gives me
Any
as error type if I set it to something other than
Throwable
for now am doing just
flatMap(List<String>::parseData)
and folding over
Validate
inside either’s right
s
I guess I confused you by using
ValidatedNel
, which is a typealias for
Validated<Nel<E, A>>
so the errors don't match here
Throwable
from the
parseData
and
List<Throwable>
for
validate()
if you use
Validated
instead of
ValidatedNel
it should work I used
ValidatedNel
in the example because it's usually used when you want to collect ALL validation errors in a list
m
and how to make it work with
ValidatedNel
?
s
mapLeft
updated:
Copy code
sealed class Error
data class FetchError(val t: Throwable) : Error()
data class ValidationError(val t: List<Throwable): Error()

fun fetchData(): Either<Error, Success> = TODO()

fun validateData(s: Success): ValidatedNel<Error, ValidData> = TODO()

fun fetchAndValidate(): Either<Error, ValidData> = 
    fetchData.
		.mapLeft<Error> { FetchError(it) }
		.flatMap { success ->
        	validateData(success).toEither()
            	.mapLeft { ValidationError(it) }
    	}
👌 1