Joram Visser
04/02/2021, 6:43 PMarrow-fx-coroutines-kotlinx-coroutines
artifact because there is no more need for suspendCancellable because Arrow Fx Coroutines is now compatible with cancelation from Kotlinx Coroutines?tDnamein
04/02/2021, 7:29 PMlistOf(1, 0, 0) > listOf(0, 1, 1) == true
listOf(0, 1, 0) > listOf(1, 0, 1) == false
Looking at the implementation I understand how this is computed but I believe this is a bug. I am not quite sure, since I do not understand how the compareTo-operator should work on lists but right now the whole outcome is determined by the comparison of the elements at index 0. And If two values at the same position are equal then the whole outcome is determined by the comparison at the next index unless the equality occurred at the end. At least to me it seems like it was not intended to work this way.ds3fdfd3
04/03/2021, 8:36 AMMike
04/04/2021, 12:31 PMtraversEither
on a List vs a Nel or am I using it wrong?
If I run below Kotest code, The Nel one ends up with 4 elements (the head gets repeated at the end of the list)
"Test traverseEither on list" {
val t = listOf(1, 2, 3).traverseEither { i ->
i.right()
}
val list = (t as Either.Right<List<String>>).value
list shouldHaveSize 3 // true [1, 2, 3]
}
"Test traversEither on NEL" {
val fromList = Nel.fromListUnsafe(listOf(1, 2, 3))
val t = fromList.traverseEither { it.right() }
val list = (t as Either.Right<List<String>>).value
list shouldHaveSize 3 // false [1, 2, 3, 1]
}
Daniel Berg
04/05/2021, 6:20 PMtraverseEither
on Nel. The behavior of traverseEither on Iterable was also different than what I expected. It walks the sequence from back to front and also f
is evaluated on all elements even if a Left value is found.tim
04/06/2021, 9:56 AMBenoît
04/06/2021, 4:29 PMMervyn McCreight
04/07/2021, 9:23 AMDaniel Ryan
04/07/2021, 9:56 AMpublic suspend fun test(): Unit {
val add1: (number: Int) -> Int = { it + 1 }
suspend fun divideBy(number: Int, divideBy: Int): Either<Throwable, Int> {
return Either.catch { number / divideBy }
}
val result = either<Throwable, Int> {
val start = 1
val i1 = add1(start)
val i2 = !divideBy(i1, 2)
val i3 = add1(i2)
add1(i3)
}
result.fold(
{ println("failed: ${it.message}") },
{ println("result: $it") }
)
}
Olivier Laforest
04/08/2021, 12:39 AMMonoK.fx {
//comprehension block
}.value()
that we use to be able to do in Arrow 0.11.0 in Arrow 0.13.x?Chris Paul
04/08/2021, 12:44 PMEither<Error, Result>
with an associated NotFound
error type or Either<Error, Result?>
Attila Domokos
04/08/2021, 1:53 PMparTupledN
and parMapN
has been moved and is now deprecated.
Is there documentation on how I could resolve this? Thank you!Josh
04/08/2021, 4:27 PM0.11.0
to 0.13.1
. How would I write this function now:
suspend fun buildPerson(): Either<DomainError, Person> {
val name: Either<DomainError, Name> = getName()
val address: Either<DomainError, Address> = getAddress()
val dob: Either<DomainError, Date> = getDOB()
return Either.applicative<DomainError>().tupledN(name, address, dob).map {
Person(name = it.a, address = it.b, dob = it.c)
}
}
Follow-up: Can I accomplish this in parallel (assuming get*
function are suspending
)?Pueffl
04/09/2021, 5:53 AMValidated.applicativeNel<Failure>()
.tupledN(
Validated.fromEither(valId).toValidatedNel(),
Validated.fromEither(valName).toValidatedNel(),
Validated.fromEither(valDescription).toValidatedNel(),
Validated.fromEither(valEmail).toValidatedNel(),
Validated.fromEither(valFrom).toValidatedNel(),
Validated.fromEither(valAuthenticationId).toValidatedNel(),
Validated.fromEither(valUrl).toValidatedNel(),
Validated.fromEither(valSettings).toValidatedNel(),
Validated.fromEither(valProperties).toValidatedNel()
)
.fix().toEither()
carbaj0
04/09/2021, 6:37 AMinterface BankGateway<F> {
fun bankAccounts(): Kind<F, Result<List<Bank>>>
}
the final implementation is ForIO, which means that, do I have to rid of it and use suspend everywhere?carbaj0
04/09/2021, 9:33 AMhttps://www.youtube.com/watch?v=CR5h2Wq1yPE&ab_channel=Intersect▾
Mervyn McCreight
04/09/2021, 11:05 AMval someList = ...
val someListOfIOs = someList.map { IO { ... } }
someListOfIOs.sequence(IO.applicativeError())
Now that IO is gone (and sequence is deprecated)? 🤔
Image I have a list of items, and want to do some side-effect actions for each, but want to short-circuit everything when the first fails.Mike
04/09/2021, 11:25 AMHugo
04/12/2021, 1:49 AMIO
to suspend
and wondering about interoperability. E.g. in this example, myFun()
works as expected, despite log(..)
being a suspended function. I believe this is because IO
now uses suspend
under the hood?
import <http://arrow.fx.IO|arrow.fx.IO>
import kotlinx.coroutines.delay
suspend fun log(message: String) {
delay(1000)
println(message)
}
fun myFun(): IO<Unit> = IO {
log("test")
}
myFun() // does nothing, suspended
myFun().unsafeRunSync() // logs "test"
Satyam Agarwal
04/13/2021, 3:51 PMList<A>
to Either<List<B>, List<C>>
just like we do for validated
We only have parTraverse and parTraverseEither.
So I can either get List<Either<B, C>>
or Either<B, List<C>>
Johan Basson
04/14/2021, 5:59 AMJörg Winter
04/14/2021, 2:12 PMeither { ... }
computation in a conventional (non-reactive, controller endpoints are not suspend!) Spring Boot RestController (for validation + effect-short-circuiting)
... what are my options: runBlocking, or some other recommended 'bridge to suspend-world' ?
Obviously this concern could become obsolete if mainstream actually moves away from 'blocking Spring', but what recommendations (if any specific exist) are there until then ?simon.vergauwen
04/14/2021, 5:15 PMJimmy Alvarez
04/14/2021, 8:30 PMrunBloking {}
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!!Cody Mikol
04/15/2021, 3:21 PMIterable<Either<L,R>>
into a Validated<Nel<L>, R>
?
For more context, I’m using parTraverse on a collection, returning an Either<L,R>
for each item. I’d like to collect that into a Validated<Nel<L>,R
to that I can take the left path if there are any errors and collect that into some useful log message.
It looks something like
items
.parTraverse { doWork(it, foo) }
.toValidated() // This is what I'm trying to figure out.
.mapLeft { makeErrorMessage(it) // where it is Nel<L> }
fun doWork() : Either<L,R>
Brad M
04/15/2021, 6:41 PMtraverseEither
for Map
, is there a parTraverseEither
?
This is what I have right now:
val items = // Map<K,V>
val newUrls = items.entries
.parTraverseEither { (key, value) -> doWork(key, value).map { Pair(key, it) } }
.map { it.associate { (first, second) -> first to second } }.bind()
Ifvwm
04/16/2021, 5:50 AMCody Mikol
04/16/2021, 1:10 PMivanmorgillo
04/18/2021, 8:33 AMEither
when Result<T>
will be easily available in Kotlin 1.5 (https://github.com/Kotlin/KEEP/pull/244)
I'm planning some lessons for my students about Either
and I'm afraid they will question the benefits
once they will be able to use Result
. I'm not sure that Result
will have flatMap
& Co. tho 🤔
Any insight? 😄ivanmorgillo
04/18/2021, 8:33 AMEither
when Result<T>
will be easily available in Kotlin 1.5 (https://github.com/Kotlin/KEEP/pull/244)
I'm planning some lessons for my students about Either
and I'm afraid they will question the benefits
once they will be able to use Result
. I'm not sure that Result
will have flatMap
& Co. tho 🤔
Any insight? 😄raulraja
04/18/2021, 9:15 AMEither
is generic in its error and left side while Result
has it’s left fixed to Throwable
.
What will happen in Arrow core is that once these restrictions are lifted and Result
becomes generically available you will see the APIs of Either
also available over Result
including support for Result
in either comprehensions and other places where its compatible. Ultimately Either is Either<E, A>
but Result is only Result<A>
where there is an implicit left Throwable embedded.ivanmorgillo
04/18/2021, 9:18 AMflatMap
on Result
?raulraja
04/18/2021, 9:19 AMresult.bind()
inside the either
and result
computation expressions.Iterable
support + comprehensions or similar. If you or anyone want to give it a shot at porting the support we’d be happy to help with any questions and review. At some point when it’s stable will be added as we had discussed this before in our planning meetings.ivanmorgillo
04/18/2021, 9:39 AMstojan
04/18/2021, 9:47 AMivanmorgillo
04/18/2021, 9:57 AMEither
most of the time we, me and my students, only use it with Throwable
.
Sometime we have a sealed class
on the left, but then we hit the infamous:
Oh now we have 15 differentAt this point I should talk about Union Types. Coproduct... and we move fromtypes, one for every possible network call that can fail 😞NoInternet
This network call can fail with an error.to
WTF is this thing!? Can't we use try/catch and return?!null
raulraja
04/18/2021, 9:59 AMsuspend () -> A
since the continuation exits always in Result<Throwable, A> and as long as you are in suspend you’ll be forced to handle at some point or blow up in suspend mainivanmorgillo
04/18/2021, 10:00 AMsealed class {
NoInternet
UserNotFound
Timeout
}
raulraja
04/18/2021, 10:00 AMGenericError(Throwable)
in the ADTivanmorgillo
04/18/2021, 10:02 AMNoInternet
and Timeout
over and overraulraja
04/18/2021, 10:03 AMivanmorgillo
04/18/2021, 10:04 AMThrowable
because I don't want my ViewModel to know that IOException
is probably the user not having internet connectionraulraja
04/18/2021, 10:05 AMsealed class Error
object NoInternet : Error()
object UserNotFound: Error()
object Timeout: Error()
sealed class UiError
data class ServiceError(val error: Error) : UiError()
object ScreenOff : UiError()
ivanmorgillo
04/18/2021, 10:05 AMsuspend fun loadUser(id): Either<Coproduct<NoInternet, TimeOut, NoUser>>, User>
raulraja
04/18/2021, 10:05 AMError
may be in a different moduleivanmorgillo
04/18/2021, 10:07 AMError
in a screen that doesn't need UserNotFound
, when I do when(error)
I get also a case that I don't need, right?raulraja
04/18/2021, 10:10 AMServiceError
or you cuold also have the Either<TypeICare, *> in that screen only. This is how decision in typing forces you to go from an error type to another across layers.ivanmorgillo
04/18/2021, 10:38 AMsuspend fun loadUser(id) : Either<XYZ, User>
suspend fun loadFriends(id) : Either<ABC, Nel<Friend>>
Both can fail with
NoInternet
SlowInternet
On top of that, the first one can fail also with UserNotFound
, while the second one can fail with NoFriendsFound
.
How could I model it to be sure that UserProfileViewModel
is able to work with
NoInternet
SlowInternet
UserNotFound
and FriendsListViewModel
can work with
kotlin
NoInternet
SlowInternet
NoFriendsFound
This is my pain point right now.stojan
04/18/2021, 11:38 AM// suspend fun loadUser(id) : Either<XYZ, User>
sealed class UserError {
object Timeout : UserError()
object NoInternet : UserError()
object UserNotFound : UserError()
}
//suspend fun loadFriends(id) : Either<ABC, Nel<Friend>>
sealed class FriendsError {
object Timeout : FriendsError()
object NoInternet : FriendsError()
object NoFriendsFound : FriendsError()
}
// We can extract duplicaton
sealed class NetworkError<A> {
object Timeout : NetworkError<Nothing>()
object NoInternet : NetworkError<Nothing>()
data class ApiError<A>(val a: A) : NetworkError<A>()
}
// Now we can use composition
object UserNotFound
typealias UserError2 = NetworkError<UserNotFound>
object NoFriendsFound
typealias FriendsError2 = NetworkError<NoFriendsFound>
// However, are we handling Timeout and NoInternet differently?
// Probably not, at most we have a different error message + retry button
// Usually we have a generic: We couldn't connect, check your network and try again
// Do we really handle UserNotFound and NoFriendsFound differently?
// From domain perspective we asked for a resource and it's not there
// We can actually handle the different error message in the VM
// In this scenario a retry would probably not help, the resource won't magically appear
sealed class ApiError {
object InternetError : ApiError() // Timeout + NoInternet
object NotFound : ApiError() // UserNotFound + FriendsNotFound
}
simon.vergauwen
04/19/2021, 7:13 AMsealed interface
in Kotlin 1.5 and later will also really help. Then you can mix in multiple sealed interfaces
into a singe ADT.