Details

    • Type: New Feature New Feature
    • Status: Open Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: 3.0
    • Component/s: groovy-jdk
    • Labels:
      None
    • Number of attachments :
      0

      Description

      Hi.

      Groovy's Closure have a name of method 'curry'.
      But this is not work for a real currying, it work as a partial function application.
      So, I wrote method of 'Real currying'.

      Referenced http://en.wikipedia.org/wiki/Currying

      Closure add = {a, b, c -> a + b + c } // Closure of adding 3 arguments.
      
      assert add(1, 2, 3) == realCurry(add)(1)(2)(3)
      assert 6 == add(1, 2, 3)
      def curriedAdd = realCurry(add)
      def curriedAdd_1 = curriedAdd(1)
      def curriedAdd_1_2 = curriedAdd_1(2)
      def addResult = curriedAdd_1_2(3)
      assert 6 == addResult
      
      def realCurry(Closure clos) {
        if (clos.maximumNumberOfParameters >= 1) {
          return { x ->
            def cc = clos.curry(x)
            if (cc.maximumNumberOfParameters) realCurry(cc)
            else cc()
          }
        } else {
          return clos
        }
      }
      

      (It's also published on gist https://gist.github.com/1193548)

      I hope this will be adopted to Groovy core.

      Thank you.

        Issue Links

          Activity

          Hide
          Masato Nagai added a comment -

          I think a thing we do to fix this issue is renaming 'curry' to 'partial'.

          Show
          Masato Nagai added a comment - I think a thing we do to fix this issue is renaming 'curry' to 'partial'.
          Hide
          CÚdric Champeau added a comment -

          Well, I think it's too late to rename curry. Just like our closures not being closures stricly speaking.

          Show
          CÚdric Champeau added a comment - Well, I think it's too late to rename curry . Just like our closures not being closures stricly speaking.
          Hide
          Pascal Schumacher added a comment -

          This is a copy of Robert Peszek comment from the closed duplicate of this issue:

          I would like to propose a new feature which would make Groovy Closures stand out from Java 8 lambdas. I would like Groovy to add support for Curried Functions.

          The following code example should explain what I mean. This code shows how partial application currently works in Groovy:

             Closure c1 = {a, b, c, d-> "${a},${b},${c},${d}"}
             Closure c2 = {a -> {b -> {c -> {d -> "${a},${b},${c},${d}"}}}}
             Closure c3 = {a, b -> {c, d -> "${a},${b},${c},${d}"}}
             
             shouldFail(MissingMethodException){ c1(1) }
             assert c1(1,2,3,4) == "1,2,3,4"
             
             shouldFail(MissingMethodException){ c2(1,2,3,4) }
             assert c2(1)(2)(3)(4) == "1,2,3,4"
             
             shouldFail(MissingMethodException){ c3(1,2,3,4) }
             shouldFail(MissingMethodException){ c3(1) }
             //... etc, etc
             
             //showcase Groovy verbose curry
             assert c1.curry(1).curry(2).curry(3).curry(4) instanceof Closure
             assert c1.curry(1).curry(2).curry(3).curry(4).call() == "1,2,3,4"
          

          Continuing the above example, imagine that Groovy has 'f' which transforms closure into a 'curried function':

             //test what Fpiglet does
             showcaseCurriedFunctions c1
             showcaseCurriedFunctions c2
             showcaseCurriedFunctions c3
          
             void showcaseCurriedFunctions(Closure c){
               Closure fc = f c //same as CallUtil.toFunction(c)
               
               assert fc(1,2,3,4) == "1,2,3,4"
               assert fc(1)(2)(3) instanceof Closure
               assert fc(1)(2)(3)(4) == "1,2,3,4"
          
               assert fc(1)(2,3,4) == "1,2,3,4"
               assert fc(1,2,3)(4) == "1,2,3,4"
               //... etc, etc
             }  
          

          Such transformation is actually not very hard to implemented and is part of Fpiglet open source: http://code.google.com/p/fpiglet/

          I believe that this functionality can be implemented better within the language.

          Why Curried Functions?
          In a nutshell, curried functions make partial application terse and intuitive. They are a great starting point towards more functional code.

          Consider these 2 code examples which do essentially the same thing:

           //Standard Groovy
           def sumSquares = list.collect{it * it}.inject{acc, el -> acc + el}
          

          and

           //curried function version may look like this (note << is both closure composition and can be used to pass argument to Closure):
           def sumSquares = reduceL(PLUS) << map(POWER(_,2)) << list
          

          (This should serve as example to show how curried functions are useful, I am not suggesting Groovy re-implements its collections API.)

          There is only one 'first class citizen' in the standard Groovy example: it is the list object, collect method is 'owned' by the list.

          By contrast, in the second example: `map`, `POWER`, `POWER(,2)`, `map(POWER(,2))`, `reduceL`, `PLUS`, `reduceL(PLUS)` are all first class citizens, they all live on their own.
          Data (`list`) and data manipulation (`reduceL(PLUS) << map(POWER(_,2))`) become decoupled.

          This input-output chain syntax is possible because of curried functions. `map` needs 2 parameters (Closure and a List) but it is given 1, `POWER` needs 2 parameters (2 numbers) but it is given 1, `reduceL` needs 2 parameters (Closure and a List) but it is given 1.

          Closures in Groovy can be viewed as first class citizens and functions.
          However, the current idiomatic usage of closures treats them
          only as either

          • short lived anonymous lambdas
          • means to achieve expressive DSL syntax (e.g. Builders)

          Function composition is supported by the language but is is never (or almost never) used by Groovy practitioners.
          Adding support for Curried Functions could change all of that and make Closures stand out more in Groovy language.

          Thank you for considering this request.
          Fpiglet implementation of this functionality can be found here:
          http://code.google.com/p/fpiglet/source/browse/#svn%2Ftrunk%2Ffpiglet%2Fsrc%2Fgroovy%2Ffpig%2Futil%2Fcurring

          Show
          Pascal Schumacher added a comment - This is a copy of Robert Peszek comment from the closed duplicate of this issue: I would like to propose a new feature which would make Groovy Closures stand out from Java 8 lambdas. I would like Groovy to add support for Curried Functions . The following code example should explain what I mean. This code shows how partial application currently works in Groovy: Closure c1 = {a, b, c, d-> "${a},${b},${c},${d}" } Closure c2 = {a -> {b -> {c -> {d -> "${a},${b},${c},${d}" }}}} Closure c3 = {a, b -> {c, d -> "${a},${b},${c},${d}" }} shouldFail(MissingMethodException){ c1(1) } assert c1(1,2,3,4) == "1,2,3,4" shouldFail(MissingMethodException){ c2(1,2,3,4) } assert c2(1)(2)(3)(4) == "1,2,3,4" shouldFail(MissingMethodException){ c3(1,2,3,4) } shouldFail(MissingMethodException){ c3(1) } //... etc, etc //showcase Groovy verbose curry assert c1.curry(1).curry(2).curry(3).curry(4) instanceof Closure assert c1.curry(1).curry(2).curry(3).curry(4).call() == "1,2,3,4" Continuing the above example, imagine that Groovy has 'f' which transforms closure into a 'curried function': //test what Fpiglet does showcaseCurriedFunctions c1 showcaseCurriedFunctions c2 showcaseCurriedFunctions c3 void showcaseCurriedFunctions(Closure c){ Closure fc = f c //same as CallUtil.toFunction(c) assert fc(1,2,3,4) == "1,2,3,4" assert fc(1)(2)(3) instanceof Closure assert fc(1)(2)(3)(4) == "1,2,3,4" assert fc(1)(2,3,4) == "1,2,3,4" assert fc(1,2,3)(4) == "1,2,3,4" //... etc, etc } Such transformation is actually not very hard to implemented and is part of Fpiglet open source: http://code.google.com/p/fpiglet/ I believe that this functionality can be implemented better within the language. Why Curried Functions? In a nutshell, curried functions make partial application terse and intuitive. They are a great starting point towards more functional code. Consider these 2 code examples which do essentially the same thing: //Standard Groovy def sumSquares = list.collect{it * it}.inject{acc, el -> acc + el} and //curried function version may look like this (note << is both closure composition and can be used to pass argument to Closure): def sumSquares = reduceL(PLUS) << map(POWER(_,2)) << list (This should serve as example to show how curried functions are useful, I am not suggesting Groovy re-implements its collections API.) There is only one 'first class citizen' in the standard Groovy example: it is the list object, collect method is 'owned' by the list. By contrast, in the second example: `map`, `POWER`, `POWER( ,2)`, `map(POWER( ,2))`, `reduceL`, `PLUS`, `reduceL(PLUS)` are all first class citizens, they all live on their own. Data (`list`) and data manipulation (`reduceL(PLUS) << map(POWER(_,2))`) become decoupled. This input-output chain syntax is possible because of curried functions. `map` needs 2 parameters (Closure and a List) but it is given 1, `POWER` needs 2 parameters (2 numbers) but it is given 1, `reduceL` needs 2 parameters (Closure and a List) but it is given 1. Closures in Groovy can be viewed as first class citizens and functions. However, the current idiomatic usage of closures treats them only as either short lived anonymous lambdas means to achieve expressive DSL syntax (e.g. Builders) Function composition is supported by the language but is is never (or almost never) used by Groovy practitioners. Adding support for Curried Functions could change all of that and make Closures stand out more in Groovy language. Thank you for considering this request. Fpiglet implementation of this functionality can be found here: http://code.google.com/p/fpiglet/source/browse/#svn%2Ftrunk%2Ffpiglet%2Fsrc%2Fgroovy%2Ffpig%2Futil%2Fcurring
          Hide
          Robert Peszek added a comment - - edited

          My apologies for entering almost duplicate ticket.

          I would like to emphasize maybe subtle but important difference in what I am proposing:

          The original proposal requires that arguments are passed to curried function one at a time. I am proposing that any valid number of arguments can be passed. Using code example from ticket description, all below should work:

           realCurry(add)(1, 2, 3)
           realCurry(add)(1)(2,3)
           realCurry(add)(1,2)(3)
           realCurry(add)(1)(2)(3)
          

          This would allow much easier to read code, using reduceL example I could write:

            reduceL(PLUS)  //partially applied
            reduceL(PLUS, list)  //evaluated
            reduceL(_, list) //maybe Groovy could support this simple syntax for partially applying second arg?
          

          Semantics: The original ticket defines real curried function as a function in curried form. My proposal defines curried function as equivalence class of functions which have the same curried form.

          The approach suggested by ticket description mimics curried functions in SCALA. What I am proposing mimics curried functions in Haskell. Why go half way only and settle on SCALA? After all how can you argue with Haskell on what curried function should be

          Again, thanks for considering my suggestions. I believe Haskell style curried functions lead to much more powerful idiomatic use.

          Show
          Robert Peszek added a comment - - edited My apologies for entering almost duplicate ticket. I would like to emphasize maybe subtle but important difference in what I am proposing: The original proposal requires that arguments are passed to curried function one at a time. I am proposing that any valid number of arguments can be passed. Using code example from ticket description, all below should work: realCurry(add)(1, 2, 3) realCurry(add)(1)(2,3) realCurry(add)(1,2)(3) realCurry(add)(1)(2)(3) This would allow much easier to read code, using reduceL example I could write: reduceL(PLUS) //partially applied reduceL(PLUS, list) //evaluated reduceL(_, list) //maybe Groovy could support this simple syntax for partially applying second arg? Semantics: The original ticket defines real curried function as a function in curried form . My proposal defines curried function as equivalence class of functions which have the same curried form. The approach suggested by ticket description mimics curried functions in SCALA. What I am proposing mimics curried functions in Haskell. Why go half way only and settle on SCALA? After all how can you argue with Haskell on what curried function should be Again, thanks for considering my suggestions. I believe Haskell style curried functions lead to much more powerful idiomatic use.
          Hide
          blackdrag blackdrag added a comment -

          Robert, my problem with this issue is still the same. I need an example, close to Groovy, that shows the benefit. Where and how exactly in reduceL(PLUS) << map(POWER(_,2)) << list you use the real currying?

          Show
          blackdrag blackdrag added a comment - Robert, my problem with this issue is still the same. I need an example, close to Groovy, that shows the benefit. Where and how exactly in reduceL(PLUS) << map(POWER(_,2)) << list you use the real currying?

            People

            • Assignee:
              Unassigned
              Reporter:
              Kentaro Yoshida
            • Votes:
              1 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

              • Created:
                Updated: