Sorry, a stupid question. It seems that all the ty...
# arrow
v
Sorry, a stupid question. It seems that all the typeclasses are deprecated. If I want to make a data class a Functor so that I can map over it and do all other familiar Functor tricks, how should I proceed with Arrow's new API?
s
Hey @Ville Peurala, It depends a little bit on the structure, so there is not a 1-fit all answer. In the current style with capabilities there is no longer a need for
map
or
flatMap
. Where
flatMap
is only still used for data types that contain
0-n
values. If you're defining a data type that requires short-circuit behavior, then you can integrate with the
Raise
DSL. https://arrow-kt.io/learn/typed-errors/working-with-typed-errors/#creating-your-own-error-wrappers (more info in the current PR, https://github.com/arrow-kt/arrow-website/pull/173). If you're modelling something concurrent like
Resource
or
Saga
, then you need to integrate with KotlinX Coroutines and rely on
suspend
. This typically entails creating an interface DSL that implements the cases of the ADT using functions and then having the cases of the interpreter implemented by the functions of the interface. Here is a tiny example, of a
Timed
data type. When we're dealing with regular data like Pair/Triple, not effect types than Functor is often considered an anti-pattern. If you have a specific example, then perhaps I am able to help.
v
Yes, I can try to explain the situation. Here is pseudocode (does not compile) of what I want:
data class CappedAmount<T>(
val uncapped: T,
val capped: T
): Functor<T> {
override fun fmap(_f_: Function<T>) = CappedAmount(f(uncapped), f(capped))
}
Concurrency is not involved, this would be "pure" code.
I have multiple places in my codebase where CappedAmount is used in a way that the same operation is done on both of the values. And no, I do not want to use
Pair
or
Triple
, I want my domain classes to have good names.
s
Right, this is not valid for
Pair
anyway. What I meant was that it's considered an anti-pattern for
Pair
since it's defined over
A, B
and
Functor#map
is then only defined over
A
or
B
so it doesn't offer a useful operation. I would also recommend using a specific domain type, rather than tuples. Unless you're in an intermediate operation, or for destructuring purposes only. It's not possible in Kotlin to offer the API you're looking for in a generic way. This requires HKTs. I am also not entirely sure if the operation you describe here is a valid
Functor
🤔 I guess it would adhere to the laws though (on top of my head). Anyhow, Kotlin cannot offer such facilities so neither can Arrow. We've felt that since the removal of this abstractions 5 years ago it resulted in more idiomatic Kotlin. Typically for your use-case we would just define a
fmap
function like you've shown here to generalise some boilerplate.
v
Okay. Thanks a lot for your quick response!