Kotlin Higher Order Function Composition
I'm trying to figure out how I can declaritively define a function as a composition of two other functions in Kotlin but I'm struggling. Here is my code:
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): Int {
return a.invoke() + b.invoke()
}
The idea of the compose function is that it will take in two functions as it's input (both of which takes two Ints and return an Int) and return the sum of the results of the two passed functions. The problem is I have to invoke the passed functions to work out their sum (obviously lol) but I don't know the values which I wish to invoke with inside the compose method (they are the values passed to the functions).
Am I completely missing something here? I know this is possible in a language like Haskell, is it possible or not in Kotlin?
kotlin
add a comment |
I'm trying to figure out how I can declaritively define a function as a composition of two other functions in Kotlin but I'm struggling. Here is my code:
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): Int {
return a.invoke() + b.invoke()
}
The idea of the compose function is that it will take in two functions as it's input (both of which takes two Ints and return an Int) and return the sum of the results of the two passed functions. The problem is I have to invoke the passed functions to work out their sum (obviously lol) but I don't know the values which I wish to invoke with inside the compose method (they are the values passed to the functions).
Am I completely missing something here? I know this is possible in a language like Haskell, is it possible or not in Kotlin?
kotlin
1
Composinga
andb
normally means applyinga
to the result ofb
applied to some argument, but this isn't what you're actually after.
– Marko Topolnik
Feb 22 '18 at 17:09
Yes. The namecompose
means some specific operation: composition of functionsf(x)
andg(x)
isg(f(x))
, not a function sum.
– Naetmul
Feb 22 '18 at 17:14
add a comment |
I'm trying to figure out how I can declaritively define a function as a composition of two other functions in Kotlin but I'm struggling. Here is my code:
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): Int {
return a.invoke() + b.invoke()
}
The idea of the compose function is that it will take in two functions as it's input (both of which takes two Ints and return an Int) and return the sum of the results of the two passed functions. The problem is I have to invoke the passed functions to work out their sum (obviously lol) but I don't know the values which I wish to invoke with inside the compose method (they are the values passed to the functions).
Am I completely missing something here? I know this is possible in a language like Haskell, is it possible or not in Kotlin?
kotlin
I'm trying to figure out how I can declaritively define a function as a composition of two other functions in Kotlin but I'm struggling. Here is my code:
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): Int {
return a.invoke() + b.invoke()
}
The idea of the compose function is that it will take in two functions as it's input (both of which takes two Ints and return an Int) and return the sum of the results of the two passed functions. The problem is I have to invoke the passed functions to work out their sum (obviously lol) but I don't know the values which I wish to invoke with inside the compose method (they are the values passed to the functions).
Am I completely missing something here? I know this is possible in a language like Haskell, is it possible or not in Kotlin?
kotlin
kotlin
asked Feb 22 '18 at 16:29
Thomas CookThomas Cook
713419
713419
1
Composinga
andb
normally means applyinga
to the result ofb
applied to some argument, but this isn't what you're actually after.
– Marko Topolnik
Feb 22 '18 at 17:09
Yes. The namecompose
means some specific operation: composition of functionsf(x)
andg(x)
isg(f(x))
, not a function sum.
– Naetmul
Feb 22 '18 at 17:14
add a comment |
1
Composinga
andb
normally means applyinga
to the result ofb
applied to some argument, but this isn't what you're actually after.
– Marko Topolnik
Feb 22 '18 at 17:09
Yes. The namecompose
means some specific operation: composition of functionsf(x)
andg(x)
isg(f(x))
, not a function sum.
– Naetmul
Feb 22 '18 at 17:14
1
1
Composing
a
and b
normally means applying a
to the result of b
applied to some argument, but this isn't what you're actually after.– Marko Topolnik
Feb 22 '18 at 17:09
Composing
a
and b
normally means applying a
to the result of b
applied to some argument, but this isn't what you're actually after.– Marko Topolnik
Feb 22 '18 at 17:09
Yes. The name
compose
means some specific operation: composition of functions f(x)
and g(x)
is g(f(x))
, not a function sum.– Naetmul
Feb 22 '18 at 17:14
Yes. The name
compose
means some specific operation: composition of functions f(x)
and g(x)
is g(f(x))
, not a function sum.– Naetmul
Feb 22 '18 at 17:14
add a comment |
3 Answers
3
active
oldest
votes
One way:
You have to pass the two Ints as additional arguments to compose
like this:
fun compose(c: Int, d: Int,
a: (Int, Int) -> Int,
b: (Int, Int) -> Int) = a(c, d) + b(c, d)
Lambdas are a further level of abstraction which give you the opportunity to make behaviour variable, you still have to provide them with data.
A more abstract approach:
You can abstract even further and let compose
return a lambda which combines the results of the other two lambdas (lets call it compose2
):
// return type is inferred to (Int, Int) -> Int
fun compose2(a: (Int, Int) -> Int, b: (Int, Int) -> Int) = {
c: Int, d: Int -> a(c, d) + b(c, d)
}
val f = compose2(/* pass lambdas */)
f
is a lambda itself an can be called like this:
f(2, 4)
So, compose2
does nothing more than return a lambda which adds the results of the two passed lambdas. The actual invocation is done outside of compose2
.
An even more abstract approach:
In your compose function you use a simple addition as composition operation. You can even make this operation variable, by passing a third lambda ab
which tells your function how to compose a
and b
:
fun compose3(a: (Int, Int) -> Int,
b: (Int, Int) -> Int,
ab: (Int, Int) -> Int) = {
c: Int, d: Int -> ab(a(c, d), b(c, d))
}
The result is, again, a lambda which takes two Ints and returns one Int.
add a comment |
You need a new function (Int, Int) -> Int
, which is the sum of two (Int, Int) -> Int
functions.
Therefore, what compose(...)
returns is another (Int, Int) -> Int
typed function.
Now, we have the type of the function compose
. It returns a function, not an Int
value.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int
How about its body?
It will return a function. Let's just return a lambda expression { x: Int, y: Int -> a(x, y) + b(x, y) }
.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int {
return { x: Int, y: Int -> a(x, y) + b(x, y)}
}
Now we can omit all the unnecessary parts.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int =
{ x, y -> a(x, y) + b(x, y) }
That's it.
add a comment |
Another worthwhile approach is to use infix extension function. For your case with parameters of type Int
it can be like this:
// Extension function on lambda
private infix fun ((Int, Int) -> Int).plus(f: (Int, Int) -> Int) = {
p1: Int, p2: Int, p3: Int, p4: Int -> this(p1, p2) + f(p3, p4)
}
// Usage
val first: (Int, Int) -> Int = { a, b -> a + b }
val second: (Int, Int) -> Int = { a, b -> a - b }
// first two parameters (1 and 2) for the `first` lambda,
// second two parameters (4 and 3) for the `second` lambda
val sum = (first plus second)(1, 2, 4, 3) // result is 4
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f48932504%2fkotlin-higher-order-function-composition%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
One way:
You have to pass the two Ints as additional arguments to compose
like this:
fun compose(c: Int, d: Int,
a: (Int, Int) -> Int,
b: (Int, Int) -> Int) = a(c, d) + b(c, d)
Lambdas are a further level of abstraction which give you the opportunity to make behaviour variable, you still have to provide them with data.
A more abstract approach:
You can abstract even further and let compose
return a lambda which combines the results of the other two lambdas (lets call it compose2
):
// return type is inferred to (Int, Int) -> Int
fun compose2(a: (Int, Int) -> Int, b: (Int, Int) -> Int) = {
c: Int, d: Int -> a(c, d) + b(c, d)
}
val f = compose2(/* pass lambdas */)
f
is a lambda itself an can be called like this:
f(2, 4)
So, compose2
does nothing more than return a lambda which adds the results of the two passed lambdas. The actual invocation is done outside of compose2
.
An even more abstract approach:
In your compose function you use a simple addition as composition operation. You can even make this operation variable, by passing a third lambda ab
which tells your function how to compose a
and b
:
fun compose3(a: (Int, Int) -> Int,
b: (Int, Int) -> Int,
ab: (Int, Int) -> Int) = {
c: Int, d: Int -> ab(a(c, d), b(c, d))
}
The result is, again, a lambda which takes two Ints and returns one Int.
add a comment |
One way:
You have to pass the two Ints as additional arguments to compose
like this:
fun compose(c: Int, d: Int,
a: (Int, Int) -> Int,
b: (Int, Int) -> Int) = a(c, d) + b(c, d)
Lambdas are a further level of abstraction which give you the opportunity to make behaviour variable, you still have to provide them with data.
A more abstract approach:
You can abstract even further and let compose
return a lambda which combines the results of the other two lambdas (lets call it compose2
):
// return type is inferred to (Int, Int) -> Int
fun compose2(a: (Int, Int) -> Int, b: (Int, Int) -> Int) = {
c: Int, d: Int -> a(c, d) + b(c, d)
}
val f = compose2(/* pass lambdas */)
f
is a lambda itself an can be called like this:
f(2, 4)
So, compose2
does nothing more than return a lambda which adds the results of the two passed lambdas. The actual invocation is done outside of compose2
.
An even more abstract approach:
In your compose function you use a simple addition as composition operation. You can even make this operation variable, by passing a third lambda ab
which tells your function how to compose a
and b
:
fun compose3(a: (Int, Int) -> Int,
b: (Int, Int) -> Int,
ab: (Int, Int) -> Int) = {
c: Int, d: Int -> ab(a(c, d), b(c, d))
}
The result is, again, a lambda which takes two Ints and returns one Int.
add a comment |
One way:
You have to pass the two Ints as additional arguments to compose
like this:
fun compose(c: Int, d: Int,
a: (Int, Int) -> Int,
b: (Int, Int) -> Int) = a(c, d) + b(c, d)
Lambdas are a further level of abstraction which give you the opportunity to make behaviour variable, you still have to provide them with data.
A more abstract approach:
You can abstract even further and let compose
return a lambda which combines the results of the other two lambdas (lets call it compose2
):
// return type is inferred to (Int, Int) -> Int
fun compose2(a: (Int, Int) -> Int, b: (Int, Int) -> Int) = {
c: Int, d: Int -> a(c, d) + b(c, d)
}
val f = compose2(/* pass lambdas */)
f
is a lambda itself an can be called like this:
f(2, 4)
So, compose2
does nothing more than return a lambda which adds the results of the two passed lambdas. The actual invocation is done outside of compose2
.
An even more abstract approach:
In your compose function you use a simple addition as composition operation. You can even make this operation variable, by passing a third lambda ab
which tells your function how to compose a
and b
:
fun compose3(a: (Int, Int) -> Int,
b: (Int, Int) -> Int,
ab: (Int, Int) -> Int) = {
c: Int, d: Int -> ab(a(c, d), b(c, d))
}
The result is, again, a lambda which takes two Ints and returns one Int.
One way:
You have to pass the two Ints as additional arguments to compose
like this:
fun compose(c: Int, d: Int,
a: (Int, Int) -> Int,
b: (Int, Int) -> Int) = a(c, d) + b(c, d)
Lambdas are a further level of abstraction which give you the opportunity to make behaviour variable, you still have to provide them with data.
A more abstract approach:
You can abstract even further and let compose
return a lambda which combines the results of the other two lambdas (lets call it compose2
):
// return type is inferred to (Int, Int) -> Int
fun compose2(a: (Int, Int) -> Int, b: (Int, Int) -> Int) = {
c: Int, d: Int -> a(c, d) + b(c, d)
}
val f = compose2(/* pass lambdas */)
f
is a lambda itself an can be called like this:
f(2, 4)
So, compose2
does nothing more than return a lambda which adds the results of the two passed lambdas. The actual invocation is done outside of compose2
.
An even more abstract approach:
In your compose function you use a simple addition as composition operation. You can even make this operation variable, by passing a third lambda ab
which tells your function how to compose a
and b
:
fun compose3(a: (Int, Int) -> Int,
b: (Int, Int) -> Int,
ab: (Int, Int) -> Int) = {
c: Int, d: Int -> ab(a(c, d), b(c, d))
}
The result is, again, a lambda which takes two Ints and returns one Int.
edited Feb 22 '18 at 17:30
answered Feb 22 '18 at 16:54
Willi MentzelWilli Mentzel
10.4k114971
10.4k114971
add a comment |
add a comment |
You need a new function (Int, Int) -> Int
, which is the sum of two (Int, Int) -> Int
functions.
Therefore, what compose(...)
returns is another (Int, Int) -> Int
typed function.
Now, we have the type of the function compose
. It returns a function, not an Int
value.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int
How about its body?
It will return a function. Let's just return a lambda expression { x: Int, y: Int -> a(x, y) + b(x, y) }
.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int {
return { x: Int, y: Int -> a(x, y) + b(x, y)}
}
Now we can omit all the unnecessary parts.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int =
{ x, y -> a(x, y) + b(x, y) }
That's it.
add a comment |
You need a new function (Int, Int) -> Int
, which is the sum of two (Int, Int) -> Int
functions.
Therefore, what compose(...)
returns is another (Int, Int) -> Int
typed function.
Now, we have the type of the function compose
. It returns a function, not an Int
value.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int
How about its body?
It will return a function. Let's just return a lambda expression { x: Int, y: Int -> a(x, y) + b(x, y) }
.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int {
return { x: Int, y: Int -> a(x, y) + b(x, y)}
}
Now we can omit all the unnecessary parts.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int =
{ x, y -> a(x, y) + b(x, y) }
That's it.
add a comment |
You need a new function (Int, Int) -> Int
, which is the sum of two (Int, Int) -> Int
functions.
Therefore, what compose(...)
returns is another (Int, Int) -> Int
typed function.
Now, we have the type of the function compose
. It returns a function, not an Int
value.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int
How about its body?
It will return a function. Let's just return a lambda expression { x: Int, y: Int -> a(x, y) + b(x, y) }
.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int {
return { x: Int, y: Int -> a(x, y) + b(x, y)}
}
Now we can omit all the unnecessary parts.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int =
{ x, y -> a(x, y) + b(x, y) }
That's it.
You need a new function (Int, Int) -> Int
, which is the sum of two (Int, Int) -> Int
functions.
Therefore, what compose(...)
returns is another (Int, Int) -> Int
typed function.
Now, we have the type of the function compose
. It returns a function, not an Int
value.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int
How about its body?
It will return a function. Let's just return a lambda expression { x: Int, y: Int -> a(x, y) + b(x, y) }
.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int {
return { x: Int, y: Int -> a(x, y) + b(x, y)}
}
Now we can omit all the unnecessary parts.
fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int =
{ x, y -> a(x, y) + b(x, y) }
That's it.
answered Feb 22 '18 at 17:09
NaetmulNaetmul
6,78953760
6,78953760
add a comment |
add a comment |
Another worthwhile approach is to use infix extension function. For your case with parameters of type Int
it can be like this:
// Extension function on lambda
private infix fun ((Int, Int) -> Int).plus(f: (Int, Int) -> Int) = {
p1: Int, p2: Int, p3: Int, p4: Int -> this(p1, p2) + f(p3, p4)
}
// Usage
val first: (Int, Int) -> Int = { a, b -> a + b }
val second: (Int, Int) -> Int = { a, b -> a - b }
// first two parameters (1 and 2) for the `first` lambda,
// second two parameters (4 and 3) for the `second` lambda
val sum = (first plus second)(1, 2, 4, 3) // result is 4
add a comment |
Another worthwhile approach is to use infix extension function. For your case with parameters of type Int
it can be like this:
// Extension function on lambda
private infix fun ((Int, Int) -> Int).plus(f: (Int, Int) -> Int) = {
p1: Int, p2: Int, p3: Int, p4: Int -> this(p1, p2) + f(p3, p4)
}
// Usage
val first: (Int, Int) -> Int = { a, b -> a + b }
val second: (Int, Int) -> Int = { a, b -> a - b }
// first two parameters (1 and 2) for the `first` lambda,
// second two parameters (4 and 3) for the `second` lambda
val sum = (first plus second)(1, 2, 4, 3) // result is 4
add a comment |
Another worthwhile approach is to use infix extension function. For your case with parameters of type Int
it can be like this:
// Extension function on lambda
private infix fun ((Int, Int) -> Int).plus(f: (Int, Int) -> Int) = {
p1: Int, p2: Int, p3: Int, p4: Int -> this(p1, p2) + f(p3, p4)
}
// Usage
val first: (Int, Int) -> Int = { a, b -> a + b }
val second: (Int, Int) -> Int = { a, b -> a - b }
// first two parameters (1 and 2) for the `first` lambda,
// second two parameters (4 and 3) for the `second` lambda
val sum = (first plus second)(1, 2, 4, 3) // result is 4
Another worthwhile approach is to use infix extension function. For your case with parameters of type Int
it can be like this:
// Extension function on lambda
private infix fun ((Int, Int) -> Int).plus(f: (Int, Int) -> Int) = {
p1: Int, p2: Int, p3: Int, p4: Int -> this(p1, p2) + f(p3, p4)
}
// Usage
val first: (Int, Int) -> Int = { a, b -> a + b }
val second: (Int, Int) -> Int = { a, b -> a - b }
// first two parameters (1 and 2) for the `first` lambda,
// second two parameters (4 and 3) for the `second` lambda
val sum = (first plus second)(1, 2, 4, 3) // result is 4
edited Jan 2 at 14:11
answered Jan 2 at 14:04


SergeySergey
4,23421835
4,23421835
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f48932504%2fkotlin-higher-order-function-composition%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Composing
a
andb
normally means applyinga
to the result ofb
applied to some argument, but this isn't what you're actually after.– Marko Topolnik
Feb 22 '18 at 17:09
Yes. The name
compose
means some specific operation: composition of functionsf(x)
andg(x)
isg(f(x))
, not a function sum.– Naetmul
Feb 22 '18 at 17:14