Kotlin Higher Order Function Composition












0















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?










share|improve this question


















  • 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











  • 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
















0















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?










share|improve this question


















  • 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











  • 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














0












0








0


1






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?










share|improve this question














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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Feb 22 '18 at 16:29









Thomas CookThomas Cook

713419




713419








  • 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











  • 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














  • 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











  • 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








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












3 Answers
3






active

oldest

votes


















1














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.






share|improve this answer

































    1














    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.






    share|improve this answer































      0














      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





      share|improve this answer

























        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
        });


        }
        });














        draft saved

        draft discarded


















        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









        1














        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.






        share|improve this answer






























          1














          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.






          share|improve this answer




























            1












            1








            1







            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.






            share|improve this answer















            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.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Feb 22 '18 at 17:30

























            answered Feb 22 '18 at 16:54









            Willi MentzelWilli Mentzel

            10.4k114971




            10.4k114971

























                1














                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.






                share|improve this answer




























                  1














                  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.






                  share|improve this answer


























                    1












                    1








                    1







                    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.






                    share|improve this answer













                    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.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Feb 22 '18 at 17:09









                    NaetmulNaetmul

                    6,78953760




                    6,78953760























                        0














                        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





                        share|improve this answer






























                          0














                          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





                          share|improve this answer




























                            0












                            0








                            0







                            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





                            share|improve this answer















                            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






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Jan 2 at 14:11

























                            answered Jan 2 at 14:04









                            SergeySergey

                            4,23421835




                            4,23421835






























                                draft saved

                                draft discarded




















































                                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.




                                draft saved


                                draft discarded














                                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





















































                                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







                                Popular posts from this blog

                                MongoDB - Not Authorized To Execute Command

                                How to fix TextFormField cause rebuild widget in Flutter

                                in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith