In Arrow, typeclasses allow you to define functional logic via extension interfaces (interfaces that define extension functions). This allows us to create implementations of a typeclass for any class, even those we do not control or that are closed for extension. This also means that the behaviors are composable since they are essentially stateless functions.
Arrow provides numerous typeclasses out of the box. Examples include the following:
- Eq: Abstracts the comparison of two instances of any data type
- Functor: Abstracts the mapping from one data type to another
- Monad: Abstracts the sequential execution of code over some collection of data
In this snippet, we've defined a filter function that takes an instance of Eq to compare strings:
fun <F> List<F>.filter(other: F, EQ: Eq<F>) =
this.filter { EQ.run { it.eqv(other) } }
We can then retrieve an existing Eq for String using an extension function:
fun main() {
listOf("1", "2", "3").filter("2", String.eq()).forEach { println(it) }
}
Typeclasses in Arrow are analogous to the functions we explored previously in the Kotlin standard library.