# currying functions

On July 28, an important event happened in the Android world: announced Jetpack Compose 1.0… Along with this innovation, the place for the keyword class even less. Kotlin supports a paradigm functional programming (FP), and Google developers make good use of this.

Object-oriented approach (OOP) is often put as opposed to FP. This is a mistake: they are not rivals and can complement each other. One of the concepts of FP is function currying. It allows you to make partial application while waiting for data, minimizing the number of errors in the code: this can be useful when developing in Compose and not only 🙂

Let’s take a look at what currying is and how you can use it in practice.

### A few words about function arguments

It’s common in the OOP world to think that functions can have multiple arguments. In fact, this is not the case. The function describes the relationship between the source (scope) and the final set of data (range). It does not connect several initial sets with a finite set.

Thus, a function cannot have multiple arguments. Basically, arguments are many:

// Привычный вид функции
fun f(a: Int, b: Int) = a + b

// Скрытый вид функции
fun f(vararg a: Int) = a.first() + a.last()

By convention, the extra code has been omitted. But it is still a function of one argument, not two.

### What is function currying

So now we know that there is one argument – an array of data (tuple). Then the function f(a, b) can be considered as the set of all functions on N from the set of all functions on N. It would look like this: f(a)(b)… In this case, you can write: f(a) = f2; f2(b) = a + b

When the function is applied f(a), argument a ceases to be a variable and becomes a constant for a function f2(b)… Execution result f(a) – a function that can be performed on a delayed basis.

Converting a function to a view f(a)(b) and is called currying, after the mathematician Haskell Curry. Although he did not invent this transformation 🙂

// Пример каррированой функции с применением fun
fun f(a: Int) = { b: Int -> a + b }

// Пример каррированой функции с применением переменной
val f2: (Int) -> (Int) -> Int = { b -> { a -> a + b } }

### Jetpack Compose and Partial Function Application

Currying allows you to split a function into several blocks and delay them as needed. There is a term for this approach – “Partial application”

I will give a practical example of partial use in Jetpack Compose. Let’s add a simple BottomNavigation with switching logic to the application, kindly generated for us by Android Studio.

CurryingTheme {

var currentTab by remember { mutableStateOf(0) }

Scaffold(
bottomBar = {
selected = currentTab == 0,
icon = { Icon(Icons.Filled.Person, null) },
onClick = {
currentTab = 0
}
)
selected = currentTab == 1,
icon = { Icon(Icons.Filled.Phone, null) },
onClick = {
currentTab = 1
}
)
}
}
) {
Greeting("Android")
}
}

Let’s tweak Greeting to switch text depending on the state of the BottomNavigation.

when (currentTab) {
0 -> Greeting("Selected - Person")
1 -> Greeting("Selected - Phone")
}

It works, but this approach is fraught with bugs: using random constants will confuse them. Let’s replace arbitrary constants with sealed classwhich will help us avoid possible problems.

}

It looks much more reliable. Let’s add another small feature – the Snackbar output when switching. In this case, he emphasizes well the importance of simplifying onClick and currying thereafter.

CurryingTheme {

val scope = rememberCoroutineScope()
val scaffoldState: ScaffoldState = rememberScaffoldState()

Scaffold(
scaffoldState = scaffoldState,
bottomBar = {
icon = { Icon(Icons.Filled.Person, null) },
onClick = {
scope.launch {
scaffoldState.snackbarHostState.showSnackbar("Selected - \${currentTab::class.simpleName}")
}
}
)
icon = { Icon(Icons.Filled.Phone, null) },
onClick = {
scope.launch {
scaffoldState.snackbarHostState.showSnackbar("Selected - \${currentTab::class.simpleName}")
}
}
)
}
}
) {
when (currentTab) {
}
}
}

Let’s say there will be more than one BottomNavigationItem. onClick looks depressing – a lot of duplicate code. This can be easily tweaked by placing the code in a nested function.

currentTab = tab
scope.launch {
scaffoldState.snackbarHostState.showSnackbar("Selected - \${currentTab::class.simpleName}")
}
}

Using this function onClick will look like this:

icon = { Icon(Icons.Filled.Person, null) },
onClick = {
}
)
icon = { Icon(Icons.Filled.Phone, null) },
onClick = {
}
)

This is a working option, but currying with partial application will help to simplify even further. onClick

// каррированая функция
fun onClick(tab: BottomNavigationTab): () -> Unit = {
currentTab = tab
scope.launch {
scaffoldState.snackbarHostState.showSnackbar("Selected - \${currentTab::class.simpleName}")
}
}
// частичное применение
icon = { Icon(Icons.Filled.Person, null) },
)