kyleg
02/03/2020, 2:10 AMLiveData
a monad that would benefit from the Rx treatment in Arrow? Its got pure
in MutableLiveData(…)
, Transformations.map(myLiveData, myTransformation)
is map
, and Transformations.switchMap(myLiveData, myTransformationFn)
is like flatMap
.
And because it is lazy until there is a registered observer, it could be thought of as IO
. I guess. IO.unsafeRunAsync
is basically SomeLiveData.observe(…)
That’s why I’m asking the experts here 🙂Kristian
02/03/2020, 10:08 AMmattmoore
02/03/2020, 7:53 PMEitherT<ForIO, E, A>
and I want to run it via parMapN
, how would I best accomplish this?Satyam Agarwal
02/04/2020, 8:41 AMIO.effect(IO.dispatchers().io() + MDCContext())
doesn’t work, but IO.effect(MDCContext())
works.
I am trying to put MDC correlation id on all the logs that gets produced on IO.dispatchers().io()
Mark Fisher
02/04/2020, 12:31 PMmattmoore
02/04/2020, 5:45 PM0.11.0-SNAPSHOT
last night using Ktor. I switched from EitherT
over to IO<E, A>
and got everything compiling and running. The weird thing is that with IO<E, A>
if I respond with A
in Ktor (where A
is the successful data class I'm expecting), A
gets serialized with { "b": { ... } }
.
At first I thought I had something still wrapped, but I inspected all the functions and types and still am getting that result. When I downgraded back to 0.10.4
and switched back to EitherT
the response serializes properly without b
and instead serializes to { ... }
. Curious if anyone else has encountered this.
Here's an example:
fun getLeads(): IO<Exception, List<Lead>> =
IO.fx<Exception, List<Lead>> {
transaction {
Leads.selectAll().map { toLead(it) }
}
}
val response = getLeads().attempt().map {
when (it) {
is Either.Left -> mapOf("error" to it.a.message)
is Either.Right -> present(it.b)
}
}
call.respond(response.suspended())
It's entirely possible I'm misusing attempt
here, not sure. The Ktor serialized response I get is:
{
"b": [
{
"id": 2,
"firstName": "Matt",
"lastName": "Moore"
}
]
}
With EitherT
:
fun getLeads(): EitherT<ForIO, Exception, List<Lead>> = EitherT(
IO {
Right(
transaction {
Leads.selectAll().map { toLead(it) }
}
)
}.handleError { Left(Exception(it.message)) }
)
val response = getLeads().value().fix().map {
when (it) {
is Either.Left -> mapOf("error" to it.a.message)
is Either.Right -> present(it.b)
}
}.suspended()
call.respond(response)
When I run this example with EitherT
I get this response from Ktor:
[
{
"id": 2,
"firstName": "Matt",
"lastName": "Moore"
}
]
Note that it no longer wraps in b
Apologies for the long message!Mark Fisher
02/05/2020, 8:31 AMwith (Option.monadError()) {
createId("123") shouldBe Some(123)
// ...
In the code above it, createId
is an extension of MonadThrow
not MonadError
so this doesn't compile.
How do I get a monadThrow
from an Option
to make this work?Kristian
02/05/2020, 10:42 AMfun prepareAndSendMultiple(listMessages: List<Message>, connectionStringKey: String, queueKey: String): IO<Unit> =
listMessages.parTraverse { message ->
prepareAndSend(message, connectionStringKey, queueKey) // returns IO<Unit>
}.unit()
?Gopal S Akshintala
02/05/2020, 11:29 AMGopal S Akshintala
02/05/2020, 2:06 PMIO
be used in conjunction with a reactive server (Like coroutines + Spring Reactor)?Ahmed Ibrahim
02/06/2020, 11:35 AMfold
. What I'm doing wrong in my case? and how can I prevent this code from crashing?
class GetStoriesListUseCase @Inject constructor(
private val hackerNewsService: HackerNewsService
) {
suspend fun topStories(
pageNumber: Int,
pageSize: Int = 100
): Either<Throwable, List<StoryUIModel>> =
readTopStoriesIds(pageSize)
.flatMap { getTopStoriesDetails(it) }
.suspended()
private fun getTopStoriesDetails(topStoriesIds: List<Id<Long>>): IO<Throwable, List<StoryUIModel>> =
topStoriesIds.map { it.value() }.parTraverse { anId ->
IO.effect(<http://Dispatchers.IO|Dispatchers.IO>) {
Timber.d("${Thread.currentThread().name}")
hackerNewsService.topStoryDetail(anId).toStoryUIModel()
}
}
private fun readTopStoriesIds(pageSize: Int): IO<Throwable, List<Id<Long>>> =
IO.effect {
hackerNewsService.topStoriesIds().map { Id.just(it) }.take(pageSize)
}
private fun StoryDetails.toStoryUIModel() =
StoryUIModel(id = id, title = title, author = by, url = url)
}
carbaj0
02/06/2020, 2:37 PMBob Glamm
02/08/2020, 4:28 AMmattmoore
02/08/2020, 4:38 AMpakoito
02/08/2020, 2:27 PMbody
here?pakoito
02/08/2020, 5:11 PMpakoito
02/10/2020, 3:00 PMBob Glamm
02/10/2020, 3:03 PMkyleg
02/10/2020, 5:16 PMStateT<ForIO, X, Y>
used to help manage state in my app, what is the benefit over a reader? when you .runM(IO.monad(), currentState)
it yields `(newState, someVal)`wrapped in IO
.
I’ve been managing state in my Android app with a private var
data class in my ViewModel representing a state object. For Id
operations, I can just use State<MyState, Unit>
to get back (newState, _)
and then myState = newState
. No problem.
But if I’m working with StateT<ForIO, MyState, Unit>
, it seems there could be race conditions doing it this way if two different state transformations are running in parallel since they’re both IO
. So I can’t just .unsafeRunAsync { … state = newState }
Instead, I can have these be StateT<ForIO, MyState, SomePartialStateChange>
and then take the partial state change and use that to update the viewmodel’s state outside the state transformation rather than reassigning the viewmodel’s state to the transformation’s returned MyState
.
But at that point, why not just use ReaderT<ForIO, MyState, SomePartialStateChange>
?
What’s the use case for StateT
if not for this example of IO
-wrapped state modification?pakoito
02/11/2020, 2:21 PM.effect
Gopal S Akshintala
02/11/2020, 5:02 PMIO
with Spring-boot for asynchronous servlets, just like returning a CompletableFuture
from a REST Controller in Spring-boot?TormentedDan
02/11/2020, 7:51 PMkyleg
02/12/2020, 4:45 PMIO.parMapN
such that I jump back into a differnet coroutinecontext after the parallel operations have completed?
IO.parMapN(IOThread, someIO, anotherIO) { a, b ->
continueOn(MainThread)
// do stuff
}
Does not appear I can call continueOn
inside parMapN
. I tried IO.parMapN(…).continueOn(MainThread)
but that doesn’t seem to actually switch me correctly. I actually have
ReaderT {
... IO.parMapN(IOThread, ...).continueOn(MainThread)
}.run(context).fix().unsafeRunAsync {
it.fold({}, { myLiveData.value = it })
}
and Android throws, telling me I can’t call setValue
from a background thread.
So the continueOn
doesn’t seem to change the coroutine context back to the main thread that way.kyleg
02/12/2020, 11:21 PMOptionT.fx {
val x: Foo = OptionT(getFoo()).bind()
val y: Bar = OptionT(getBar()).bind()
}.value().fix().unsafeRunAsync {}
errors out at val y = …
saying cannot cast Foo
to Bar
. There’s no compile-time error, getFoo(): IO<Option<Foo>>
and getBar(): IO<Option<Bar>>
Furthermore, for the exact same user input on the exact same data set, it only occurs sometimes. getFoo
and getBar
wrap DB calls that return Foo?
and `Bar?`` to make them IO<Option<Foo/Bar>>
Might be my last question for a while! Tomorrow I go pick up a laptop from a client and boss has been joking that I’m going to be putting on 60 hours a week for a while on a project, and I have a baby due in a week. 😄 God willing, work and the baby are both chill.Dasyel Willems
02/13/2020, 10:14 AMDerek Towriss
02/13/2020, 8:02 PMSatyam Agarwal
02/14/2020, 12:48 PMGiorgio Antonioli
02/14/2020, 5:17 PMFilterIndex
without succeeding):
val lens = MyClass.listProperty
.every(ListFilterForIndex { index -> index % 2 })
.itemProperty
var myObject = MyClass()
myObject = lens.modify(myObject) { "modified string" }
Jannis
02/15/2020, 12:17 PMList.map
from the kotlin stdlib is an inline function and thus allows suspend functions inside of it if the scope from which it is called allows it. Option.map
and pretty much all other arrow functions are not inline and thus don't allow it. Not entirely sure what the design decision is, but that is the reason this does not work ^^simon.vergauwen
02/15/2020, 12:19 PMtraverse
is absolutely what you want here. Not map { !otherCode() }
simon.vergauwen
02/15/2020, 12:19 PMtraverse
is absolutely what you want here. Not map { !otherCode() }
Gopal S Akshintala
02/15/2020, 12:29 PMprivate fun optionMapper() = fx.monad {
getOptionString().traverse(Option.monad()) { booleanInput(!getIsSomethingTrueInHigherKind(it)).toOption() }}