Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-6281

Add Support for curried functions - make Groovy more functional

    XMLWordPrintableJSON

Details

    • New Feature
    • Status: Closed
    • Major
    • Resolution: Duplicate
    • None
    • None
    • syntax
    • None

    Description

      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

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              robert_peszek Robert Peszek
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: