<@UE3D4UE15> I think the importance of Bracket bec...
# arrow
r
@Bob Glamm I think the importance of Bracket becomes more apparent when you compare examples. For example the fact that coroutines are eager makes them an issue for error handling and safe resource release in some scenarios:
b
Illustrating how useful Bracket is was the easy part (thankfully :)). I just need a test to proves it behaves the way I expect
And I'm curious about what good approaches to the tracing/value threading problem are in general. (E.g. if I want to carry some state along with the computation without modifying the method signatures)
r
In my opinion StateT is not worth it in Kotlin because the same can be achieved making the state an abstract algebra in tagless you just inject where needed
StateT will add the state to the signature but the algebra would flatten it.
If you plan to use StateT as target you can depend on MonadState or even easier roll your own algebra with the state ops you need and that is parametric to F
👌 1
Creating custom tagless algebras and uberinterpreters that provide proof of a runtime can be done in Kotlin with simple interfaces and a module that provides runtime proof
l
In the gist, can the following emit multiple values? (similarly to RxJava observable)
Copy code
val account = getProcessedAccount().bind()
r
yes,
bind
gets translated to flatmap. For example when binding is over a non deterministic monad like List this is equivalent:
Copy code
listOf(1, 2, 3).flatMap { n -> listOf(n + 1) }

ListK.fx {
  val n = listOf(1, 2, 3).bind()
  n + 1
}
Something to keep in mind though is that monads that produce multiple values need to be handled with care because you can’t apply local substitution without altering the meaning of the program. for example:
Copy code
fx {
  val (a) = listOf(1, 2)
  val (b) = listOf(true, false)
  a toT b
}
vs
Copy code
fx {
  val (b) = listOf(true, false)
  listOf(1, 2) toT b
}
if you replace
a
by it’s bound value you would get different results that if you bind over
a
.
Other langs like Scala enforce binding being a special lang construct that is applied in order bound one val at a time. See Scala’s for comprehensions. But in Kotlin binding can happen freely anywhere in the expression body which is a lot more powerful syntactically than scala’s but at the risk of loosing this local property.
Fear not Arrow meta plugins are coming to warn users of these code concerns inspecting projects for better FP patterns 🙂
l
Have you used this to model complex UI apps?
r
You mean bind? Yes many Android projects use Fx with Rx to achieve imperative syntax over the chain
Not myself but others in my company are using it that way
l
Do you know how they model UI events? I’m curious to see purely functional approach to UI development.
r
@simon.vergauwen or @Jorge Castillo may know more about how Rx is being used to model those event when mixing Arrow and Android
s
@laimiux I am using Arrow, Rx in an Android project to do pure FP in UI development
It’s very nice! I am hope to have some time to work out a complex example in the future
If you have any specific questions I’d be happy to help out 🙂
l
Are you using some form of unidirectional state management using reducers?
s
That’s exactly what I am doing. Rx for streaming UI events to the domain layer, Rx for streaming a
sealed
model to the UI and the domain layer part is what you’d do for any other FP app
I expose my UI as an interface, which I can then integrate in the domain layer and easily stub away
Copy code
typealias Refresh = Unit
data class Item(val id: String)

interface HomeScreen {
   suspend fun render(home: HomeViewModel)
   fun refresh(): Observable<Refresh>
   fun itemSelected(): Observable<Item>
   ...
}
Also Optics (DSL) is awesome for reducing boilerplate and increasing expressiveness with state reducers!
l
What are some strategies you use to handle configuration changes? Or does the state management live outside of Activity/Fragment?
I’ve looked into optics/lenses before. Really nice approach, but I’m hesitant due to build impact from code-gen.
s
What are your concerns about the code-gen? I’ll be porting it to compiler plugins soon, which should get rid of the nasty compile times of kapt
For configuration chance I’ve used a RxRelay in the passed https://github.com/JakeWharton/RxRelay. It’s a subject that can’t
onError
or
onComplete
, and you can hold a
BehaviorRelay
which caches it’s last value in your Fragment. Since Fragments are retained over config chance and only their views are destroyed you can simply use the `BehaviorRelay`’s last cached value to redraw your views.
Although with MPP in mind I’ve changed strategy a bit and I prefer to avoid such platform details from my business logic. So I prefer to keep all domain data in a data store, which fits perfectly in the picture of unidirectional data flow.
l
Yep, kapt was my primary concern regarding optics. We also use
RxRelays
for retaining last emitted state. Though, for events we moved to a render model concept ->
ButtonRenderModel(val text: String, val onClick: () -> Unit)
so the UI is not aware of event/message passing solution.
What’s the boundary between Rx & arrow.IO ?
s
You can mix and match them while supporting cancelation support.
Copy code
fun <A> Single<A>.asIO(): IO<A> = IO.concurrent().cancelable<A> { cb ->
  val disposable = subscribe({ a -> cb(Right(a)) }, { e -> cb(Left(e)) })
  IO { disposable.dispose() }
}.fix()

fun <A> IOOf<A>.asSingle(): Single<A> = Single.create { emitter -> 
  val disposable = fix().unsafeRunAsyncCancellable { either -> 
    either.fold({ e -> emitter.tryOnError(e) }, { a -> emitter.onSuccess(a) })
  }
  emitter.setCancellable { disposable.invoke() }
}
IO
has some more complex concurrency constructs common in FP such as
bracketCase
,
parTraverse
& co and it has a pure API. RxJava takes a slightly different approach with an impure API, it currently also has some operators that Arrow doesn’t have yet so that goes both ways atm.
I take a different approach than you do with
ButtonRenderModel
. However that is still has an impure API, changing that to
ButtonRenderModel(val text: String, val onClick: suspend () -> Unit)
makes it pure and you can easily integrate it in your Arrow Fx program.
l
I agree, it’s impure. I don’t use
suspend
in this place because the
onClick
callback is used within Android framework
buttonView.setOnClickListener { renderModel.onClick() }
Do you know if the goal is to have operator parity with RxJava?
s
I wouldn’t call it operator parity because we’ll be implementing things differently. i.e. instead of the
retry
and co operators we’d probably introduce a
Schedule
data type which represents how you want to retry. https://github.com/zio/zio/blob/master/docs/datatypes/schedule.md That would allow you to define your retry mechanisms separately and make them compose. Beside that
IO
surpasses
Single
operator wise, but I’d have to put the 2 next to each-other.
What is missing atm is streams, which is the biggest pain atm but all the efforts in Arrow Fx were to prepare for Streams so hopefully they should appear on the list in the near future if time allows for it 🙂
l
Thanks for the info! I was also curious how similar it is to
zio
(not that I’m very knowledgeable on it).