Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to chain lambdas to a resulting lambda in Kotlin?

... or the equivalent of java.util.Function.andThen()

In Java

Function<String, String> add1 = string -> string + "1";
Function<String, String> add2 = string -> string + "2";
Function<String, Strint> add12 = add1.andThen(add2);

add12.apply("") returns "12"

How would I write it in Kotlin?

val add1 = { string:String -> string + "1" }
val add2 = { string:String -> string + "2" }
val add12 = ?
like image 719
Pedro Borges Avatar asked Dec 31 '22 12:12

Pedro Borges


2 Answers

The feature you're looking for is called function composition. As far as I can tell, it doesn't come built-in to Kotlin (would love to be corrected on this). But it's very easy to write as an extension function.

infix fun<A, B, C> ((B) -> C).compose(that: (A) -> B): (A) -> C =
  { this(that(it)) }

Now we can write

val add1 = { string:String -> string + "1" }
val add2 = { string:String -> string + "2" }

println((add2 compose add1)("3")) // Prints "312"

I write compose to use right-to-left composition, more in line with the way mathematical functions work.

like image 54
Silvio Mayolo Avatar answered Jan 03 '23 05:01

Silvio Mayolo


Granted, this is not exactly what you're looking for, because you can't store a composed function this way in a variable, but you can chain the results of functions using run if the functions themselves don't have the parameter as a receiver:

fun print(string: String) {
    println(add1(string).run(add2))
}

// or

fun print(string: String) {
    println(string.run(add1).run(add2))
}

Since run is an inline function, it doesn't add a wrapper object around each function.

The let function will have the exact same effect. This is because when you pass something other than a lambda to a higher order function, it doesn't matter if the first parameter is a receiver or not. They are treated as the same signature.

like image 26
Tenfour04 Avatar answered Jan 03 '23 03:01

Tenfour04