Jimmy Alvarez
04/15/2021, 1:47 AMfun getUsers(max: Int): Either<LowUnprotectedError, List<User>>
and the other one is the validate method fun isCandidateToDelete(user: User): Either<LowUnprotectedError, Boolean>
.
Then i need to star the process for each user, but given the method to validate the user is in a Either, I need to fold it in order to know the result of verification like this :
val usersDelete = users.filter { repository.isCandidateToDelete(it).fold({ false }, { it }) }`
Could you imagine a better way to accomplish this process.
Please let me know if i was not clear with this question, thanks in advance!!simon.vergauwen
04/15/2021, 6:57 AMeither
computation block should work perfectly for you here. You can use either { }
for suspend
code or either.eager
for non-suspending code.
And you can rewrite your code to the following snippet:
import arrow.core.computations.either
suspend fun program(): Either<LowUnprotectedError, List<User>> =
either {
val users = getUsers(100).bind()
users.filter { isCandidate(it).bind() }
}
simon.vergauwen
04/15/2021, 6:58 AMbind()
can safely extract the value from Either.Right
and when Either.Left
is encountered then it just exits the either { }
block with the Left
value.
This allows for writing code with Either
in an imperative way ๐Jimmy Alvarez
04/15/2021, 2:08 PMreturn either.eager<LowUnprotectedError, List<ProcessResult>> {
val users = repository.getUsers(350000).bind()
val usersToKillSession = users.filter { repository.isCandidateToKillSession(it).fold({ false }, { it }) }
usersToKillSession.map { user -> publishUsersResult(user) } + enrolledUsers.map { user -> deleteUsersResult(user) }
}.fold(
{
LOGGER.error("Error processing users. Cause: ${it.cause}")
ResponseEntity<Response>(HttpStatus.OK)
},
{
it.forEach { <http://LOGGER.info|LOGGER.info>("User: ${it.user}. result: ${it.msj}. error: ${it.cause}") }
ResponseEntity<Response>(HttpStatus.OK)
}
)
Jimmy Alvarez
04/15/2021, 2:08 PMsimon.vergauwen
04/15/2021, 4:27 PMval users: List<User> = repository.getUsers(350000).bind()
val errorOrResult = users.map { isCanidateToKillSession(it) }
val (errors, results) = errorsOrResults.separateEither()
Where seperateEither
splits Iterable<Either<A, B>>
into Pair<List<A>, List<B>>
so you can inspect all left sides and all right sides in the list.
Additionally, since you are doing map
here on Iterable
instead of traverse all your elements will be processed without short-circuiting.Jimmy Alvarez
04/15/2021, 7:39 PMJimmy Alvarez
04/15/2021, 7:39 PMJimmy Alvarez
04/15/2021, 7:40 PMJimmy Alvarez
04/15/2021, 8:00 PMisCanidateToKillSession
we lose user
object so by the time you need to log which users were killed basically you could not access it. you loosed that context.Jimmy Alvarez
04/15/2021, 8:03 PMsimon.vergauwen
04/16/2021, 8:34 AMEither<LowProtectedError, Boolean>
from isCandidateToKillSession
but Either<LowProtectedError, User>
or Either<LowProtectedError, ProcessedUser>
Jimmy Alvarez
04/16/2021, 2:47 PMsimon.vergauwen
04/16/2021, 3:27 PM