How to use IO compositions in arrow-kt within sync context - kotlin

I have following interfaces:
interface UserRepository {
fun role(codename: String): IO<Option<Role>>
fun accessRights(roleId: Long): IO<List<AccessRight>>
}
Now trying to use it to compose effectfful operations like this:
private fun retrieveRole(roleCodename: String): IO<Option<RoleTo>> =
IO.fx {
val role = userRepository.role(roleCodename).bind()
role.map { r ->
val ar = userRepository.accessRights(r.id).bind()
RoleTo.of(r, ar)
}
}
The code fails to compile on the second bind (call to userRepository.accessRights(r.id).bind() since bind is suspend function. How I can properly compose two operations? I don't get why first bind works but second doesn't and I don't want to make my function suspend or I have to do it anyway?

This is one frequent gotcha. If you have Option<A> or Either<E, A> and you'd like to act on it, your first instinct is to use it on the block:
either.map { !someIO }
The problem is that the left/none option isn't covered. You should act on both sides, and extract out the IO before executing it.
!either.fold({ ioLogError(it) }, { someIo })
For now, as of 0.10, because fold is an inline function you can use ! inside it too. I cannot promise that'll be the case in the future, as this is an unintended behavior of inline that we left for convenience.

I was able to solve issue using traverse and applicative instance of IO:
private fun retrieveRole(roleCodename: String): IO<Option<RoleTo>> =
IO.fx {
val role = userRepository.role(roleCodename).bind()
val accessRights = role.traverse(IO.applicative()) {
userRepository.accessRights(it.id)
}.bind()
role.map2(accessRights) {
(r, ar) -> RoleTo.of(r, ar)
}
}
Thanks for pointing out about the fact that map expects pure functions.

Related

Emit data to kotlin's flow from regular java function

I have an external interface which I cannot change:
interface ExternalApi {
fun onDataReceived(data: String)
}
I need to start consuming data and send it to flow. Data order is a necessity. I'd like to have a cold flow, but I couldn't find a version of cold flow with emit function, so I used hot flow + replay set to Max value as a workaround. Here was my first try:
class FlowProblem {
val flow: MutableSharedFlow<String> = MutableSharedFlow(replay = Int.MAX_VALUE)
fun startConsuming() {
object : ExternalApi {
override fun onDataReceived(data: String) {
flow.emit(data)
}
}
}
}
Unfortunately it doesn't work as emit function is a suspended function. However this is an external interface and I cannot add suspend modifier. I tried to also do something like this:
override fun onDataReceived(data: String) {
val coroutineScope = CoroutineScope(Job())
coroutineScope.launch {
flow.emit(data)
}
}
but for me it's kind a silly to create new coroutine only in order to move data to flow. I'm also wondering about data order.
What should I do? Maybe flow/channel is not suitable here and I should pick something another?
Thanks IR42, callbackFlow was exactly what I needed.

Kotlin add custom method to stream chaining

I need to add a custom method (which is a Consumer) to the dot chaining in stream api, i not sure how to do it, following is my code.
If that is not possible, is there anyway to do it with other operation? Maybe like with .map or something else?
fun main(args: Array<String>) {
var countries: List<String> = listOf("India", "Germany", "Japan")
var firstCountry = countries.stream()
.filter{it == "Germany"}
.performOperation{} //not sure what to do here
.findFirst()
println(firstCountry)
}
fun performOperation(country: String) {
if(country.length > 3) {
throw InvalidLengthException("Error")
}
//do some operation, won't return any value
doCustomOperation(country)
}
You may already be aware that when it comes to steams there are two types of operations, one is your map, filter etc. known as intermediate opeartion and others are terminal operations such as forEach. You said your custom operation wont return any value, hence making it a terminal operation. moreover it seems to me that you want to perform same operation for all the elements, basically a forEach. for this you can define an extension function on Stream as
fun <T> Stream<T>.someOperation(operation: (T) -> Unit){
this.forEach { operation(it) }
}
There is two ways to do what you want.
var firstCountry = countries.stream()
.filter{it == "Germany"}
.also(::performOperation)
.findFirst()
The :: is a function reference and is basically the same as .also { performOperation(it)}
The second one would be to make your own extension method on list. I wouldn't recommend it until you understand kotlin lambdas and extension methods
fun Stream<String>.performOperation(): Stream<String> {
for(country in this) {
if(country.length > 3) {
throw InvalidLengthException("Error")
}
doCustomOperation(country)
}
return this
}
You would just call that one like .performOperation() where you have the .performOperation{}

How can I access the context in every function of a call chain with Kleisli?

I have a call chain of some methods, where I pass a context via a Kleisli. Basically I want to pass a context down to the db access layer, but I want to access this context everywhere in between.
The following example works perfectly. My problem though is, that I want to access the context in OrderService.findAll(...) as well. I tried several approaches but I keep failing.
object OrderRepository {
fun findAll(userId: String): Kleisli<Context, ForIO, List<Order>> =
Kleisli { ctx ->
IO {
ctx.db.query("someQuery")
}
}
}
object OrderService {
fun findAll(userId: String): Kleisli<Context, ForIO, List<OrderResponse>> =
OrderRepository.findAll(userId).map(IO.monad()) { orderList ->
orderList.map {
//Create OrderResponse from Order
}
}
}
Is it possible to access the context there, or doesn't this make any sense? Thanks for the help :)
what you need is a Kleisli from D to D, with D as the Context. That way you would have D (context) as the result type also, and you'd be able to flatMap and get access to it. That is why the method ask() provides, available over the companion.
Let's say your OrderRepository is also a dependency in the Context instead of a pure function (for the sake of the example), so you need to access it from within the context in the service. See:
interface OrderApi
interface OrderDB {
fun query(query: String): List<Order> = TODO()
}
data class Order(val id: String)
data class OrderResponse(val order: Order)
data class Context(val api: OrderApi, val repository: OrderRepository, val db: OrderDB)
class OrderRepository {
fun findAll(userId: String): Kleisli<Context, ForIO, List<Order>> =
Kleisli { ctx ->
IO {
ctx.db.query("someQuery")
}
}
}
object OrderService {
fun findAll(userId: String): Kleisli<Context, ForIO, List<OrderResponse>> {
val monad = IO.monad()
return Kleisli.ask<Context, ForIO>(monad).flatMap(monad) { ctx ->
ctx.repository.findAll(userId).map(monad) { orderList ->
orderList.map { OrderResponse(it) }
}
}
}
}
That said, Kleisli is a Monad transformer (also called ReaderT) that can be a bit convoluted to work with. If you want to inject dependencies on a functional codebase and stay simpler, my advice is to go for extension functions over a Context receiver, which already implicitly passes your dependencies across al levels, which is described on this post by Paco.
#brewcode #bob there is a higher-order pattern in FP above the kinds of encodings like MTL and that is delimited continuations, the mother of all monads. That subsumes to imperative syntax the entire Functor hierarchy including monads like readers bringing application syntax to the environment through continuations. This is what kotlin suspension is.
#Jorge Castillo question is right but any lang with continuations support has better abstractions than wrapping in data types at allocation cost.
For JS and TS instead of the Haskell like encoding that ReaderT or any callback style encoding like the ones Scala and Haskell propose one based on delimited continuations if there is a way in those languages would be much cleaner and easier to use to beginners than wrapped callback style as ReaderT proposes. Look at the program below and see if this has any drawbacks over the wrapped version.
interface OrderApi
interface OrderDB {
fun query(query: String): List<Order> = TODO()
}
data class Order(val id: String)
data class OrderResponse(val order: Order)
data class Context(
val api: OrderApi,
val repository: OrderRepository,
val db: OrderDB) : OrderApi by api, OrderRepository by repository, OrderDB by db
interface OrderRepository {
suspend fun Context.findAll(userId: String): List<Order> =
query("someQuery")
}
object OrderService {
suspend fun Context.findAll(userId: String): List<OrderResponse> =
findAll(userId).map(::OrderResponse)
}

Kotlin - Automatically match overriden function type?

I'm trying to write a function that is essentially a wrapper method around some other functionality, for instance, some logging function.
I've tried several combinations of inline, generic, reified, etc., but nothing seems to work.
My function looks like this:
fun log(note: String, block: () -> Unit): () -> Unit {
print(note)
return block
}
My idea here is to perform some simple operation on the incoming note, and then just return that incoming function to be used as it was originally.
However, I want to do this around overridden functions like so:
override fun onClick(clicked: View) = log("Green Button") {
// here the regular onClick functionality goes
}
Here, I get an error "Return type is () -> Unit, which is not a subtype of overridden". This makes sense enough, as the function signatures do not match.
However, when I do this with other random functions:
fun test() = log("foo") { ... }
fun otherTest(a: String, b: Int) = log("bar") { ... }
I get no errors, and the interpreter somehow seems fine with this. I also tried looking at something like GlobalScope.launch to take that approach, but I couldn't figure it out.
Is what I'm trying to do possible? If not, is there something close?
I think
inline fun log(note: String, block: () -> Unit): Unit {
print(note)
return block()
}
should do what you want. It can be generalized to
inline fun <T> log(note: String, block: () -> T): T {
print(note)
return block()
}
I get no errors, and the interpreter somehow seems fine with this.
Why is that surprising? Those functions just return () -> Unit. If you do e.g.
fun test() = log("foo") { print("bar") }
then calling test() won't print bar; calling test()() will.
Tell me if my understanding is wrong. This is my approach
Extension function:
fun View.onClickWithLog(str: String, l: () -> Unit) {
setOnClickListener { Log.d("LogTag", str); run(l) }
}
Usage (from Activity):
btnTest.onClickWithLog("My Button String"){
Log.d("Actions from Activity", "Content")
finish()
}
and the output is
D/LogTag: My Button String
D/Actions from Activity: Content
which prints your note first, and execute the actions in the lambda expression.
When you use the = operator to assign something to a fun, the expression on the right hand side is supposed to return the return type of that fun
The original fun onClick(clicked:View) : Unit has return type Unit. When you write
override fun onClick(clicked:View) = ... , the ... is what you get when you call onClick(v) so it should be a Unit instead of a View -> Unit (Not even () -> Unit as in your code)
Take a simpler example. Let say you have fun sum(a:Int,b:Int) : Int. When you write override fun sum(a:Int,b:Int) = ... , ... must be an Int instead of a (Int,Int) -> Int since you expect to get an Int immediately when you call sum(a,b). If you somehow got a let say
val someOtherWayToSum : (Int,Int) -> Int = {...}
and want to use it, you can write
override fun sum(a:Int,b:Int) = someOtherWayToSum(a,b)
In your case, you better just do
override fun onClick(clicked:View){
/* some operation (e.g your log)*/
/* the regular onClick functionality */
}
since you are overriding it and implementing its regular functionality right there anyway.

How to Resolve Function Template Generics for Signal/Slot System?

I'm trying to develop a simplistic signals/slots system in Kotlin. Here's what I have so far:
open class Signal<T : Function<Unit>>() {
val callbacks = mutableListOf<T>()
open fun addCallback(slot: T) {
callbacks.add(slot)
}
open fun emit(vararg params: Any) {
for(call in callbacks) {
call(*params)
}
}
}
fun test(myarg: Int) = println(myarg)
fun main(args: Array<String>) {
val myevent = Signal<(Int) -> Unit>()
myevent.addCallback(::test)
myevent.emit(2)
}
The idea is one would create an instance of Signal along with a generic template to dictate which parameters are used for the callbacks. Callbacks can then be added to the Signal. Finally, whenever the Signal needs to be... well... "signaled", the emit method is used. This method passes all the parameters to the corresponding callbacks if necessary.
The issue is this code results in the following error:
kotlin\Signal.kt:30:4: error: expression 'call' of type 'T' cannot be invoked as a function. The function 'invoke()' is not found
The line in question is:
call(*params)
Any recommendations on how to handle things from here?
This is because Function is an empty interface (source).
The various function types that actually have invoke operators are all defined one by one here, as Function0, Function1, etc.
I don't think you'll be able to create a Signal implementation that may have callbacks with any number and any type of parameters. Could you perhaps get by with only having callbacks with a single parameter?
open class Signal<T> {
val callbacks = mutableListOf<(T) -> Unit>()
open fun addCallback(slot: (T) -> Unit) {
callbacks.add(slot)
}
open fun emit(param: T) {
for (call in callbacks) {
call(param)
}
}
}
fun test(myarg: Int) = println(myarg)
fun main(args: Array<String>) {
val myevent = Signal<Int>()
myevent.addCallback(::test)
myevent.emit(2)
}
(Note that you could replace both usages of (T) -> Unit here with Function1<T, Unit>.)