• Post Reply Bookmark Topic Watch Topic
  • New Topic

Java 8 - is it really doing function currying?  RSS feed

 
Scott Shipp
Ranch Hand
Posts: 223
12
Eclipse IDE IntelliJ IDE Java Scala Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I was reading this article on how Java 8 doesn't really have currying. I looked around the web and a lot of examples are out there using the lambda syntax (->) but all they are doing is using it as syntactic sugar for:



"add2" method here is not a curried function. It just forwards along to another method.

So does Java 8 really have function currying?? I've been using Scala for awhile now which has real function currying.
 
Pierre-Yves Saumont
Author
Ranch Hand
Posts: 103
17
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Scott,

Being the author of this article, my opinion is probably biased! However, to the exact question "does Java 8 really have function currying in the same way Scala has?", the answer is no. But neither Scala not Java "have" function currying. What Scala has is syntactic sugar for function currying. Function currying is not a feature a language has or has not.

First, one must acknowledge the fact that there is no such thing as a function of several arguments. A function is an application from a set to another set. It can't be an application from several sets to one set. So it can only have one argument. What people call functions of several arguments are in fact functions of tuples. For example, the following function:

is a function of one argument, the tuple (x, y), which is a single element of the product of two sets, and the product of two sets is a single set. If x and y are positive integers, (x, y) is an element of the set of all possible pairs of positive integers.

In Java 8, a function may be represented by a method, such as:

or by a function:

or by a method reference:

(Note that properties and method may have the same name, although this does not make things easy to read!)

Currying is useful in many cases if you need the two values of the tuple to be evaluated separately. For example, you may use the f function to compute the area of rectangles. But if you have rectangles of width 2, 3 and 4 and varying length, it could be useful to build three specialized functions for this: f2 for computing the area of rectangles of width 2, f3 for rectangles of width 3, and so on.

You can write specific methods or functions for this, from scratch, such as:

or

But this is not at all currying. Currying is the fact to write a function that is equivalent to f but that allows applying each element of the tuple argument one at a time, as if one could write:

but this of course does not compile. For this, one need to write a curried version of the function. Applying the first argument will return a function taking the second argument. Thus the type of the function is:

where is the argument type, and is the return type.

As you can see, there is no way to do this with methods, since you can't return a method. You can however return a method reference, but the type is still a function. The complete curried function is:

This is currying. So you can't say that a language has it or not. It's up to you to implement it. What Scala has is syntactic sugar for applying functions. The computation of the area of a rectangle of width 2 and length 5 could be written in Java as:

or

In Scala, one can write:

Beside this syntactic sugar, currying in Java is done exactly as in Scala.

Two things are worth noting:
  • Using the curried form allows writing function of "any number of arguments" where Java 8 only has BiFunction.
  • Using the curried form does not allow using method references (at list in a simple way), so it might not allows as much optimization from the compiler and/or the JVM

  • For more information about currying, see my book Functional Programming in Java in which I also present automatic currying an uncurrying.


     
    Stephan van Hulst
    Saloon Keeper
    Posts: 7719
    142
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Great detailed answer Pierre-Yves!

    The only thing I can add is an example of how currying works in a purely functional language such as Haskell.

    Let's take the foldl function, which takes a binary operator, an identity and a list of elements, and folds (or reduces) the list by applying the operator to all the elements of the list. Here's the declaration:

    You can use it to sum a list of numbers:
    This expression returns 0+1+2+3=6.

    To make this less onerous we can define the sum function:

    We provided the foldl function with an operator, and got a function that takes a number and a list of numbers, and which returns a number.

    Then we provided *that* function with the additive identity 0, and got a function which takes a list of numbers, and returns the sum of that list.
     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!