I'm using Arrow in my Kotlin backend project. I have repositories like this:
interface UserRepository {
fun user(username: String): Try<Option<User>>
}
Now I want to go step further and abstract from concrete Try type with returning Kind<F, Option<User>> instead. I was able to do it with this code:
interface UserRepository<F> {
fun user(username: String): Kind<F, Option<User>>
}
class IdRepository : UserRepository<ForId> {
fun user(username: String): Kind<ForId<Option<User>>> =
if (username == "known") Id.just(Some(User()))
else Id.just(None)
}
But now I'm struggling to use it. I don't understand how we can say that the F in userRepository has to be a Monad, so that it can be used in monad comprehension block. Suppose I have some class defined like this:
class UserService<F>(ME: MonadError<F, Throwable>, repo: UserRepository<F>)
: MonadError<F, Throwable> by ME {
fun someOperations(username: String) : Kind<F, User> = bindingCatch {
val (user) = repo.user(username)
user.fold({ /* create user */ }, { /* return user */ })
}
}
The compiler complains that it can't bind user on line repo.user as it requires the Kind<ForTry, ...> but the repo.user returns Kind<F, ...> which is unknown here. How to properly achieve abstraction from Try so that I can implement repositories with Id instances and how to use such repositories in service classes?
In 0.10.0 you can use the Fx type class to perform monad bind. It's variants are available as described in the kdoc over your example where each one of them represents the level of power you want. In practice, most apps use IO.fx since effects can only be purely encapsulated in IO. You may only replace runtimes as long as they support suspension if you are working with side effects so this basically narrows down your runtime options to instances of Async<F> since suspension implies potential async work. That is IO, Rx, etc... but never Try, Either, ... those are good for eager non-effectful pure computations
/**
* Fx allows you to run pure sequential code as if it was imperative.
*
* #see [arrow.typeclasses.suspended.monad.Fx] // Anything with flatMap
* #see [arrow.typeclasses.suspended.monaderror.Fx] //Try, Either etc stop here
* #see [arrow.fx.typeclasses.suspended.monaddefer.Fx] // IO
* #see [arrow.fx.typeclasses.suspended.concurrent.Fx] // IO
*/
class UserService<F>(ME: MonadError<F, Throwable>, repo: UserRepository<F>)
: MonadError<F, Throwable> by ME {
fun someOperations(username: String) : Kind<F, User> =
fx.monadThrow {
val user = !repo.user(username)
user.fold({ /* create user */ }, { /* return user */ })
}
}
}
If you'd like a more detailed explanation swing by the https://slack.kotlinlang.org #arrow channel and we'll be happy to help and hang out and discuss FP in Kotlin
Cheers!
Related
I am just wondering what is the benefit of using the operator invoke than not using it. I am trying it out on one of my interfaces to see what the benefits are.
fun interface MapperDomainToData<in E, out M> {
operator fun invoke(entity: E): M
}
fun interface MapperDomainToData<in E, out M> {
fun map(entity: E): M
}
In my implementation there seems to be no difference. In fact I prefer not using it as the method name is more meaningful.
class MapSocialLoginRequestImp #Inject constructor() : MapperDomainToData<SocialLoginRequestEntity, SocialLoginRequestModel> {
override fun invoke(entity: SocialLoginRequestEntity): SocialLoginRequestModel {
return SocialLoginRequestModel(
token = entity.token,
provider = entity.provider
)
}
override fun map(entity: SocialLoginRequestEntity): SocialLoginRequestModel {
return SocialLoginRequestModel(
token = entity.token,
provider = entity.provider
)
}
}
I think the second implementation is the more clear as the map method is more readable.
The difference isn't in how you declare the interface implementation, but only in how you use the interface object. Of course there's no difference in your code.
The difference is between
myMapper(entity)
and
myMapper.map(entity)
To be clear, it's entirely reasonable to prefer the second one, but that's the difference that the invoke operator function provides.
I'm in the process of trying to port some code I wrote in Java over to Kotlin and I'm struggling mightily with some issues around generics. I quite commonly use a factory pattern in Java to return an instance of a generic interface that I want to call for a given type.
In Java I had this contract:
public Message<T extends Action> {
private List<T> actions;
..some other properties
}
And this interface:
public interface MessageConverter<T extends Action, M extends BaseModel> {
List<M> convertMessage(Message<T> message);
DataType getDataType();
}
And lastly this factory:
public class MessageConverterFactory {
//This gets populated via DI
private Map<DataType, MessageConverter> converterMap;
public <T extends Action, M extends BaseModel> MessageConverter<T, M> getMessageConverter(DataType dataType) {
return converterMap.get(dataType);
}
}
With all that in place, I was able to do things like this:
Message<T> message = mapper.readValue(messageString, type);
MessageConverter<T, M> messageConverter = messageConverterFactory.getMessageConverter(dataType);
List<M> dataModels = messageConverter.convertMessage(message);
I understand that I was abusing raw generic types in Java to an extent to make this happen, but I assumed there would be some way to still do a generic factory pattern like this.
However, no matter with I try with generic variance, star projections, etc. I cannot get Kotlin to accept any version of this code. The closest I got was down to the invocation of the generic converter's convertMessage call. It was failing because I was using star projections and attempting to restrict the type of T, but that was leading to the compiler thinking convertMessage accepts Message<Nothing>.
Is code like this possible in Kotlin? Or is there a similar alternative approach I should be using instead?
Thanks,
Jeff
The literal conversion of this to Kotlin is pretty simple, and the Java-to-Kotlin converter built in to IDEA would spit something like this out almost directly, given the equivalent Java code:
class Message<T: Action> {
private val actions: List<T> = TODO()
...
}
interface MessageConverter<T: Action, out M: BaseModel> {
fun convertMessage(message: Message<T>): List<M>
val dataType: DataType
}
class MessageConverterFactory(val converterMap: Map<DataType, MessageConverter<*, *>>) {
fun <T: Action, M: BaseModel> getMessageConverter(dataType: DataType): MessageConverter<T, M> {
return converterMap[dataType] as MessageConverter<T, M>
}
}
Note, the cast in getMessageConverter -- your Java code is doing the equivalent, without being explicit about it -- I believe the compiler would even spit out a warning about an unchecked assignment.
An alternative in Kotlin is to use an inline function with reified types to return the appropriate converter. For example, something like this:
inline fun <reified T: Action, reified M: BaseModel> converterOf(): MessageConverter<T, M> = when {
T::class == FooAction::class, M::class == BarModel::class -> TODO()
else -> error("No converter available for type ${T::class.simpleName} to ${M::class.simpleName}")
}
Disclaimer upfront: Recently, my interest in functional programming has grown and I've been able to apply the most basic approaches (using pure functions as much as my knowledge and working environment permits) in my job. However, I'm still very inexperienced when it comes to more advanced techniques and I thought trying to learn some by asking a question on this site might be the right idea. I've stumbled over similar issues once every while, so I think there should be patterns in FP to deal with this type of problems.
Problem description
It boils down to the following. Suppose there is an API somewhere providing a list of all possible pets.
data class Pet(val name: String, val isFavorite: Boolean = false)
fun fetchAllPetsFromApi(): List<Pet> {
// this would call a real API irl
return listOf(Pet("Dog"), Pet("Cat"), Pet("Parrot"))
}
This API knows nothing about the "favorite" field and it shouldn't. It's not under my control. It's basically just returning a list of pets. Now I want to allow users to mark pets as their favorite. And I store this flag in a local database.
So after fetching all pets from the api, I have to set the favorite flag according to the persisted data.
class FavoriteRepository {
fun petsWithUserFavoriteFlag(allPets: List<Pet>) {
return allPets.map { it.copy(isFavorite = getFavoriteFlagFromDbFor(it) }
}
fun markPetAsFavorite(pet: Pet) {
// persist to db ...
}
fun getFavoriteFlagFromDbFor(pet: Pet): Boolean {...}
}
For some reason, I think this code dealing with the problem of "fetch one part of the information from one data source, then merge it with some information from another" might benefit from the application of FP patterns, but I'm not really sure in which direction to look.
I've read some of the documentation of Arrow (great project btw :)) and am quite a Kotlin enthusiast, so answers utilizing this library would be very appreciated.
Here's something I'd potentially do. Your code has a couple of important flaws that make it unsafe from the functional programming perspective:
It doesn't flag side effects, so compiler is not aware of those and cannot track how they're are used. That means we could call those effects from anywhere without any sort of control. Examples of effects would be the network query or all the operations using the database.
Your operations don't make explicit the fact that they might succeed or fail, so callers are left to try / catch exceptions or the program will blow up. So, there's not a strong requirement to handle both scenarios, which could drive to missing some exceptions and therefore get runtime errors.
Let's try to fix it. Let's start by modeling our domain errors so we have a set of expected errors that our domain understands. Let's also create a mapper so we map all potential exceptions thrown to one of those expected domain errors, so our business logic can react to those accordingly.
sealed class Error {
object Error1 : Error()
object Error2 : Error()
object Error3 : Error()
}
// Stubbed
fun Throwable.toDomainError() = Error.Error1
As you see, we're stubbing the errors and the mapper. You can put time on designing what errors you'll need for your domain on an architecture level and write a proper pure mapper for those. Let's keep going.
Time for flagging our effects to make the compiler aware of those. To do that we use suspend in Kotlin. suspend enforces a calling context at compile time, so you cannot ever call the effect unless you're within a suspended environment or the integration point (a couroutine). We are going to flag as suspend all operations that would be a side effect here: the network request and all db operations.
I'm also taking the freedom to pull out all DB operations to a Database collaborator just for readability.
suspend fun fetchAllPetsFromApi(): List<Pet> = ...
class FavoriteRepository(private val db: Database = Database()) {
suspend fun petsWithUserFavoriteFlag(allPets: List<Pet>) {
... will delegate in the Database ops
}
}
class Database {
// This would flag it as fav on the corresponding table
suspend fun markPetAsFavorite(pet: Pet): Pet = ...
// This would get the flag from the corresponding table
suspend fun getFavoriteFlagFromDbFor(pet: Pet) = ...
}
Our side effects are safe now. They've become description of effects instead, since we cannot ever run them without providing an environment capable of running suspended effects (a coroutine or another suspended function). In functional jargon we'd say our effects are pure now.
Now, let's go for the second issue.
We also said that we were not making explicit the fact that each effect might succeed or fail, so callers might miss potential exceptions thrown and get the program blown up. We can raise that concern over our data by wrapping it with the functional Either<A, B> data type. Let's combine both ideas together:
suspend fun fetchAllPetsFromApi(): Either<Error, List<Pet>> = ...
class FavoriteRepository(private val db: Database = Database()) {
suspend fun petsWithUserFavoriteFlag(allPets: List<Pet>): Either<Error, List<Pet>> {
... will delegate in the Database ops
}
}
class Database {
// This would flag it as fav on the corresponding table
suspend fun markPetAsFavorite(pet: Pet): Either<Error, Pet> = ...
// This would get the flag from the corresponding table
suspend fun getFavoriteFlagFromDbFor(pet: Pet): Either<Error, Boolean> = ...
}
Now this makes explicit the fact that each one of those computations might succeed or fail, so the caller will be forced to handle both sides and will not forget about handling the potential errors. We're using the types in our benefit here.
Let's add the logics for the effects now:
// Stubbing a list of pets but you'd have your network request within the catch block
suspend fun fetchAllPetsFromApi(): Either<Error, List<Pet>> =
Either.catch { listOf(Pet("Dog"), Pet("Cat")) }.mapLeft { it.toDomainError() }
We can use Either#catch to wrap any suspended effects that might throw. This automatically wraps the result into Either so we can keep computing over it.
More specifically, it wraps the result of the block in Either.Right in case it succeeds, or the exception into Either.Left in case it throws. We also have mapLeft to map potential exceptions thrown (Left side) to one of our strongly typed domain errors. That is why it returns Either<Error, List<Pet>> instead of Either<Throwable, List<Pet>>.
Note that with Either we always model errors on the left side. This is by convention, since Right represents the happy path and we want our successful data there, so we can keep computing over it with map, flatMap, or whatever.
We can apply the same idea for our db methods now:
class Database {
// This would flag it as fav on the corresponding table, I'm stubbing it here for the example.
suspend fun markPetAsFavorite(pet: Pet): Either<Error, Pet> =
Either.catch { pet }.mapLeft { it.toDomainError() }
// This would get the flag from the corresponding table, I'm stubbing it here for the example.
suspend fun getFavoriteFlagFromDbFor(pet: Pet): Either<Error, Boolean> =
Either.catch { true }.mapLeft { it.toDomainError() }
}
We're stubbing the results again, but you can imagine we'd have our actual suspended effects loading from or updating the DB tables inside each Either.catch {} block above.
Finally, we can add some logic to the repo:
class FavoriteRepository(private val db: Database = Database()) {
suspend fun petsWithUserFavoriteFlag(allPets: List<Pet>): Either<Error, List<Pet>> =
allPets.map { pet ->
db.getFavoriteFlagFromDbFor(pet).map { isFavInDb ->
pet.copy(isFavorite = isFavInDb)
}
}.sequence(Either.applicative()).fix().map { it.toList() }
}
Ok this one might be a bit more complex due to how our effects are written, but I'll try to make it clear.
We need to map the list so for each pet loaded from network we can load its fav state from the Database. Then we copy it as you were doing. But given getFavoriteFlagFromDbFor(pet) returns Either<Error, Booelan> now we'd have a List<Either<Error, Pet>> as a result 🤔 That might make it hard to work with the complete list of pets, since we'd need to iterate and for each one first we'd need to check whether it's Left or Right.
To make it easier to consume the List<Pet> as a whole, we might want to swap the types here, so we'd have Either<Error, List<Pet>> instead.
To this magic, one option would be sequence. sequence requires the Either applicative in this case since that'll be used to lift the intermediate results and the final list into Either.
We're also using the chance to map the ListK into the stdlib List instead, since ListK is what sequence uses internally, but we can understand it as a functional wrapped over List in broad words, so you have an idea. Since here we're only interested on the actual list to match our types, we can map the Right<ListK<Pet>> to Right<List<Pet>>.
Finally, we can go ahead and consume this suspended program:
suspend fun main() {
val repo = FavoriteRepository()
val hydratedPets = fetchAllPetsFromApi().flatMap { pets -> repo.petsWithUserFavoriteFlag(pets) }
hydratedPets.fold(
ifLeft = { error -> println(error) },
ifRight = { pets -> println(pets) }
)
}
We're going for flatMap since we have sequential ops here.
There are potential optimizations we could do like using parTraverse to load all the fav states from DB for a list of pets in parallel and gather results in the end, but I didn't use it since I'm not sure your database is prepared for concurrent access.
Here's how you could do it:
suspend fun petsWithUserFavoriteFlag(allPets: List<Pet>): Either<Error, List<Pet>> =
allPets.parTraverse { pet ->
db.getFavoriteFlagFromDbFor(pet).map { isFavInDb ->
pet.copy(isFavorite = isFavInDb)
}
}.sequence(Either.applicative()).fix().map { it.toList() }
I think we could also simplify the whole thing a bit more by changing some of the types and how operations are structured but wasn't sure about refactoring it too much from your codebase since I'm not aware of your current team constraints.
And here's the complete codebase:
import arrow.core.Either
import arrow.core.extensions.either.applicative.applicative
import arrow.core.extensions.list.traverse.sequence
import arrow.core.extensions.listk.foldable.toList
import arrow.core.fix
import arrow.core.flatMap
data class Pet(val name: String, val isFavorite: Boolean = false)
// Our sealed hierarchy of potential errors our domain understands
sealed class Error {
object Error1 : Error()
object Error2 : Error()
object Error3 : Error()
}
// Stubbed, would be a mapper from throwable to any of the expected domain errors used via mapLeft.
fun Throwable.toDomainError() = Error.Error1
// This would call a real API irl, stubbed here for the example.
suspend fun fetchAllPetsFromApi(): Either<Error, List<Pet>> =
Either.catch { listOf(Pet("Dog"), Pet("Cat")) }.mapLeft { it.toDomainError() }
class FavoriteRepository(private val db: Database = Database()) {
suspend fun petsWithUserFavoriteFlag(allPets: List<Pet>): Either<Error, List<Pet>> =
allPets.map { pet ->
db.getFavoriteFlagFromDbFor(pet).map { isFavInDb ->
pet.copy(isFavorite = isFavInDb)
}
}.sequence(Either.applicative()).fix().map { it.toList() }
}
class Database {
// This would flag it as fav on the corresponding table, I'm stubbing it here for the example.
suspend fun markPetAsFavorite(pet: Pet): Either<Error, Pet> =
Either.catch { pet }.mapLeft { it.toDomainError() }
// This would get the flag from the corresponding table, I'm stubbing it here for the example.
suspend fun getFavoriteFlagFromDbFor(pet: Pet): Either<Error, Boolean> =
Either.catch { true }.mapLeft { it.toDomainError() }
}
suspend fun main() {
val repo = FavoriteRepository()
val hydratedPets = fetchAllPetsFromApi().flatMap { pets -> repo.petsWithUserFavoriteFlag(pets) }
hydratedPets.fold(
ifLeft = { error -> println(error) },
ifRight = { pets -> println(pets) }
)
}
Hello dear reactive programmers, I started to learn project reactor but I still struggle to figure out what operator to use when. I figured out, that if I want to have reusable parts to define a reactor flow, I can use the transform operator. What I would like to achieve is to use a certain implementation of such a flow function based on the current observables context. For a Mono flow, I came up with this, but I am very unsure, if it is a good solution:
So here is a part of the flow
class CloudeventOverDelegatorRoute(
val fromHttpToDelegatorRoute: FromHttpToDelegatorRoute,
val delegatorProvider: DelegatorProvider,
val fromDelegatorToHttpRoute: FromDelegatorToHttpRoute
): MessageRoute<HttpBaseMessage, HttpResponseMessage> {
override fun isHandlerFor(context: RouteContext): Boolean {
return fromHttpToDelegatorRoute.isHandlerFor(context)
&& fromDelegatorToHttpRoute.isHandlerFor(context)
}
override fun buildPipeline(input: Mono<RoutableMessage<HttpBaseMessage>>): Mono<RoutableMessage<HttpResponseMessage>> {
var dynamicallyDeterminedDelegator: Delegator? = null
return input.transform {
fromHttpToDelegatorRoute.buildPipeline(input)
}.handle<RoutableMessage<InternalMessage>> { t, u ->
dynamicallyDeterminedDelegator = delegatorProvider.provideDelegatorFor(t.routeContext)
u.next(t)
u.complete()
}.transform {
dynamicallyDeterminedDelegator!!.sendDelegated(it)
}.transform { fromDelegatorToHttpRoute.buildPipeline(it) }
}
}
Here is the dynamic selection logic
interface DelegatorProvider {
fun provideDelegatorFor(context: RouteContext): Delegator
}
class FirstMatchDelegatorProvider(
private val delegators: List<Delegator>
): DelegatorProvider {
override fun provideDelegatorFor(context: RouteContext): Delegator {
return delegators.firstOrNull {
it.isHandlerFor(context)
}?: throw IllegalStateException("No Delegator route available for context: $context")
}
}
And this is the delegator providing an essential sub-part of the whole flow
interface Delegator {
fun isHandlerFor(context: RouteContext): Boolean
fun sendDelegated(input: Mono<RoutableMessage<InternalMessage>>): Mono<RoutableMessage<InternalStatusMessage>>
}
What do you think? How would you solve it?
this approach is problematic because it relies on shared state (the dynamicallyDeterminedDelegator variable). If multiple subscribers subscribe to the returned Mono, they could overwrite each other delegator. Maybe that (multiple subscriptions) can't happen in your application, but this is a very bad habit to get into in any case.
looks like you can derive a delegator out of a RoutableMessage<InternalMessage> , and that you don't really need to retain that delegator.
the easiest way to resolve and apply the delegator to the routableMessage in one go is simply to use flatMap. see the (pseudo) java code below:
.flatMap(routableMessage -> {
val delegator = delegatorProvider.provideDelegatorFor(routableMessage.routeContext);
return delegator.sendDelegated(routableMessage);
})
I'm trying to keep this minimal, but let me know if I'm being too minimal.
Suppose you have a class hierarchy like this, designed for generating HTML (inspired by the Kotlin tutorial; semi-pseudocode follows):
class Tag {
protected val children = arrayListOf<Tag>()
operator fun String.unaryPlus() = children.add(Text(this))
}
class TagWithChildren : Tag() {
fun head(init: Head.() -> Unit) = initializeTag(Head(), init)
fun script(init: Script.() -> Unit) = initializeTag(Script(), init)
fun <T : Tag> initializeTag(tag: T, init: T.() -> Unit): T {
tag.init()
children.add(tag)
return tag
}
}
class Head : TagWithChildren()
class Script : Tag()
class Text(val str: Text) : Tag()
Notice that Head has head and script methods while Script doesn't.
Now you can construct a template that looks like this:
head {
script {
+"alert('hi');"
}
}
Which works great! However, if the block passed to script tries to call methods that aren't available on Script, it can call the method on Head instead. For example,
head {
script {
script {
+"alert('hi');"
}
}
}
not only isn't a compile error, it's actually equivalent to
head {
script {
}
script {
+"alert('hi');"
}
}
which is super confusing, from a template author's perspective.
Is there any way to prevent method lookups from traveling up the scope like that? I only want it to look at the innermost scope.
UPDATE 11/24/2016:
Kotlin 1.1-M03 has introduced scope control, which I believe solves exactly this problem. https://blog.jetbrains.com/kotlin/2016/11/kotlin-1-1-m03-is-here/
The current behavior is intentional. Code in a lambda has access to receivers of all enclosing scopes. It is possible that a future version of Kotlin will add a modifier that will restrict a lambda with receiver to calling methods on that receiver only and not the enclosing scopes, but in the current version there's no way to change that behavior.
As a workaround, I can have it fail at runtime if I change the classes to look like this:
open class Tag {
operator fun String.unaryPlus()
// pulled up from TagWithChildren, call protected method
fun head(init: Head.() -> Unit) = addChild(Head())
fun script(init: Script.() -> Unit) = addChild(Head())
// throws in Tag
open protected fun addChild(t: Tag) = throw IllegalArgumentException()
}
class TagWithChildren : Tag() {
// overridden to not throw in subclass
protected override fun addChild(t: Tag) = children.add(t)
}
This way, every Tag has the builder methods (solving the scoping problem), but actually calling them may result in a runtime failure.