Kotlin supports Higher order functions. In this blog, I will create a higher order function that will use map & fold right for execution.
Before diving into higher order functions, let’s go through map & fold right.
map
is collective transform operation.
var numbers = mutableListOf(1, 2, 3)
numbers = numbers.map { it*2 }.toMutableList()
// elements in numbers: 2,4,6
foldRight
accept initial state, apply initial state to all elements and return final state.
var numbers = mutableListOf(1, 2, 3)
var result = numbers.foldRight(100, {a,b -> test(a,b)})
private fun test(a: Int, b: Any): Int {
return a + b as Int
}
/*
First execution:
initial 100
a = 3
b = 100
Second Execution
a = 2
b = 103
Third Execution
a = 1
b = 105
final: result = 106
*/
Let’s create a higher order function Middleware
that takes an instance StringApp
, has inner function next: Type
and return Type
.
typealias Type = (value: String) -> Unit
typealias Middleware = (stringApp: StringApp) -> (next: Type) -> Type
Now, create three classes that implements Middleware
.
class MiddlewareA : Middleware {
override fun invoke(stringApp: StringApp) = { next: Type ->
{ value: String ->
next("$value MiddlewareA ")
}
}
}
class MiddlewareB : Middleware {
override fun invoke(stringApp: StringApp) = { next: Type ->
{ value: String ->
next("$value MiddlewareB ")
}
}
}
class MiddlewareC : Middleware {
override fun invoke(stringApp: StringApp) = { next: Type ->
{ value: String ->
next("$value MiddlewareC ")
}
}
}
StringApp
class receives list of middlewares and call dispatch
to execute higher order function.
class StringApp(private val middlewares: MutableList<Middleware>) {
private fun reduce(value: String) {
val result = value;
// result =
}
fun dispatch(value: String) {
var dispatch2 = middlewares[2](this)(::reduce)
var dispatch1 = middlewares[1](this)(dispatch2)
middlewares[0](this)(dispatch1)(value)
}
}
The higher order function can be written as below:
val app = StringApp(mutableListOf(MiddlewareA(), MiddlewareB(), MiddlewareC()))
app.dispatch("init")
{
middlewareC -> set string value to "init middleware A middleware B middleware C"
{
middlewareB -> set string value to "init middleware A middleware B"
{
middlewareA -> set string value to "init middleware A"
}
}
}
Let’s use map & fold right to execute higher order function.
class StringApp(middlewares: MutableList<Middleware>) {
// map inject store reference to all middleware functions
private val middlewareMap: List<(Type) -> Type> =
middlewares.map { m -> m.invoke(this) }
/*
// now below code execution required to achieve result
var dispatch2 = middlewareMap[2](::reduce)
var dispatch1 = middlewareMap[1](dispatch2)
middlewareMap[0](dispatch1)(value)
*/
var middlewareDispatch = compose(middlewareMap)(::reduce)
// traverse through middlewares
// build middleware chain by injecting dispatch from previous middleware
// inject ::reduce to last middleware
private fun compose(functions: List<(Type) -> Type>): (Type) -> Type =
{ dispatch ->
functions.foldRight(
dispatch,
{ nextDispatch, composed -> nextDispatch(composed) })
}
private fun reduce(value: String) {
val result = value;
}
private fun dispatch(value: String) {
middlewareDispatch(value)
}
}
I learned map & fold while implementing redux middleware concepts from library kotlin-redux.
Using higher order functions for middleware helps to stop middleware chain execution. If a middleware subscribes to service, on async callback the middleware can finish the work without invoking next middleware.