This article explains how to create an Android app using higher order types and how to switch between RxJava to Coroutines with one line by abstracting away to technology chosen in your application.

The code for the article can be found in this repository.

1 — Intro

So Kotlin doesn't have Higher order types =|. But don't feel bad about it, because you can use Arrow to emulate then! Uhuu! Although you cannot have a syntax like this one:

F<A>

You can emulate it with a syntax like this:

Kind<F, A> // you have Kind<F, A> = F<A>

And you can take advantage of a much more powerful type system. It can be really useful to build a DSL where you don't need to choose the wrapper for your data until the very last moment. This can be very useful to change technologies if you decide to in a latter moment. If you're not sure about using RxJava or Coroutines, for example, not to worry, you can change it with just a single line of code.

If you are more interested about how the Kind of Arrow works, you can take a look a this presentation: https://www.youtube.com/watch?v=ERM0mBPNLHc

2 — The project

We are going to create an app that looks a lot like the one from this article. if you didn't read it, that's fine, I'll explain. It is an app that shows the repositories of Java in the Github. Like this:

And that's it. Just one screen. Pretty simple, right?

The app is made using MVP, because it is a simple and easy to follow architecture. So, shall we start?

2 — The presentation layer

That's the code of our presenter:

So, what's the first parameter of this constructor? MonadDefer?

MonadDefer is a type of monad capable of deferring the computation, so you can run it in a later moment. We use it to create our Monad Comprehension with bindingCancellable. It returns the Kind that we are hopping to get and also a Disposable instance. We you can invoke in the disposable and the value binded (kind in this example) is lifted to BindingCancellationException, so the action doesn't complete. We invoke all disposables in a method in our presenter that should be called in the onPause() moment of the activity's lifecycle.

So what Monad are we going to use? It doesn't matter! It could be an Observable, Single or an IO using Coroutines, but his will concretised in a later moment. For now, all we care is that we call our Use Case and we bind the result to kind. So let's go to our model layer.

3 — Model Layer

Arrow has a integration module with Retrofit, available prior the version 0.8.0. We are going to use this module to simplify our code. First we need to add it in our project.

Then we can create our endpoints requesting CallK as the return type.

CallK offers a way to run the OkHttp requests and return the response wrapped inside a a given Monad. I'll a show an example of use in the 4.2 section. Let's move on for now.

3.1 — Use Case

Very simple class:

Ok. We just called our dataSource. So let's go there.

3.2— DataSource

All we have is a comprehension and a call to our apiClient.

After we use async we get a Response from CallK. Response has already a extension function to unwrap the body in a monadic way.

4 — The Activity

After we create our structure in a Monadic way. All we need to do is to provide a Monad to run our logic.

So that's what I have in my Activity:

So now we concretised our implementation to RxJava using the integration of Arrow. But one thing really nice about our approach is that we can change our monad with just one command. If we no longer want to use RxJava, that’s ok. Just change the monad being used and that’s it. Like this:

And we have the same results. Here's what I got:

You can use this same approach to work with so many other cases like building a framework, a DSL a command line user interface… You decide, just keep in mind that with this approach you can let the choose for a specific type to a later moment and create code that is a lot easier to change and adapt.

5 — Bonus: Using delegation to improve the code.

So a interesting improvement that can be done in our code is to use our components as Monad an avoid using our Async<F> dependencies every where.

This can be done with delegation. I will let the code of the improvement so you can use it as an example for you next Arrow project.

Presenter:

Use case:

Data source:

So that's it!

I hope you enjoyed the article!

Happy coding!