Does Java support Currying?

36,832

Solution 1

Java 8 (released March 18th 2014) does support currying. The example Java code posted in the answer by missingfaktor can be rewritten as:

import java.util.function.*;
import static java.lang.System.out;

// Tested with JDK 1.8.0-ea-b75
public class CurryingAndPartialFunctionApplication
{
   public static void main(String[] args)
   {
      IntBinaryOperator simpleAdd = (a, b) -> a + b;
      IntFunction<IntUnaryOperator> curriedAdd = a -> b -> a + b;

      // Demonstrating simple add:
      out.println(simpleAdd.applyAsInt(4, 5));

      // Demonstrating curried add:
      out.println(curriedAdd.apply(4).applyAsInt(5));

      // Curried version lets you perform partial application:
      IntUnaryOperator adder5 = curriedAdd.apply(5);
      out.println(adder5.applyAsInt(4));
      out.println(adder5.applyAsInt(6));
   }
}

... which is quite nice. Personally, with Java 8 available I see little reason to use an alternative JVM language such as Scala or Clojure. They provide other language features, of course, but that's not enough to justify the transition cost and the weaker IDE/tooling/libraries support, IMO.

Solution 2

Currying and partial application is absolutely possible in Java, but the amount of code required will probably turn you off.


Some code to demonstrate currying and partial application in Java:

interface Function1<A, B> {
  public B apply(final A a);
}

interface Function2<A, B, C> {
  public C apply(final A a, final B b);
}

class Main {
  public static Function2<Integer, Integer, Integer> simpleAdd = 
    new Function2<Integer, Integer, Integer>() {
      public Integer apply(final Integer a, final Integer b) {
        return a + b;
      }
    };  

  public static Function1<Integer, Function1<Integer, Integer>> curriedAdd = 
    new Function1<Integer, Function1<Integer, Integer>>() {
      public Function1<Integer, Integer> apply(final Integer a) {
        return new Function1<Integer, Integer>() {
          public Integer apply(final Integer b) {
            return a + b;
          }
        };
      }
    };

  public static void main(String[] args) {
    // Demonstrating simple `add`
    System.out.println(simpleAdd.apply(4, 5));

    // Demonstrating curried `add`
    System.out.println(curriedAdd.apply(4).apply(5));

    // Curried version lets you perform partial application 
    // as demonstrated below.
    Function1<Integer, Integer> adder5 = curriedAdd.apply(5);
    System.out.println(adder5.apply(4));
    System.out.println(adder5.apply(6));
  }
}

FWIW here is the Haskell equivalent of above Java code:

simpleAdd :: (Int, Int) -> Int
simpleAdd (a, b) = a + b

curriedAdd :: Int -> Int -> Int
curriedAdd a b = a + b

main = do
  -- Demonstrating simpleAdd
  print $ simpleAdd (5, 4)

  -- Demonstrating curriedAdd
  print $ curriedAdd 5 4

  -- Demostrating partial application
  let adder5 = curriedAdd 5 in do
    print $ adder5 6
    print $ adder5 9

Solution 3

There are a lot of options for Currying with Java 8. Function type Javaslang and jOOλ both offering Currying out of the box (I think this was an oversight in the JDK), and Cyclops Functions module has a set of static methods for Currying JDK Functions and method references. E.g.

  Curry.curry4(this::four).apply(3).apply(2).apply("three").apply("4");

  public String four(Integer a,Integer b,String name,String postfix){
    return name + (a*b) + postfix;
 }

'Currying' is also available for Consumers. E.g to return a method with 3 params, and 2 of those already applied we do something similar to this

 return CurryConsumer.curryC3(this::methodForSideEffects).apply(2).apply(2);

Javadoc

Solution 4

EDIT: As of 2014 and Java 8, functional programming in Java is now not only possible, but also not ugly (I dare to say beautiful). See for example Rogerio's answer.

Old answer:

Java isn't best choice, if you are going to use functional programming techniques. As missingfaktor wrote, you will have to write quite big amount of code to achieve what you want.

On the other hand, you are not restricted to Java on JVM - you can use Scala or Clojure which are functional languages (Scala is, in fact, both functional and OO).

Solution 5

Currying requires to return a function. This is not possible with java (no function pointers) but we can define and return a type that contains a function method:

public interface Function<X,Z> {  // intention: f(X) -> Z
   public Z f(X x);
}

Now let's curry a simple division. We need a Divider:

// f(X) -> Z
public class Divider implements Function<Double, Double> {
  private double divisor;
  public Divider(double divisor) {this.divisor = divisor;}

  @Override
  public Double f(Double x) {
    return x/divisor;
  }
}

and a DivideFunction:

// f(x) -> g
public class DivideFunction implements Function<Double, Function<Double, Double>> {
  @Override
  public function<Double, Double> f(Double x) {
    return new Divider(x);
  }

Now we can do a curried division:

DivideFunction divide = new DivideFunction();
double result = divide.f(2.).f(1.);  // calculates f(1,2) = 0.5
Share:
36,832
user855
Author by

user855

Updated on July 08, 2022

Comments

  • user855
    user855 almost 2 years

    I was wondering if there is any way to pull that in Java. I think it is not possible without native support for closures.

  • missingfaktor
    missingfaktor almost 13 years
    @OP: Both are executable code snippets and you can try them out at ideone.com.
  • missingfaktor
    missingfaktor almost 13 years
    What does currying have got to do with loops?! At least look up the term before you answer a question about it.
  • Vishy
    Vishy almost 13 years
    @missingFaktor, curried functions are usually applied to collections. e.g. list2 = list.apply(curriedFunction) where curriedFunction might be 2 * ? In Java you would do this with a loop.
  • missingfaktor
    missingfaktor almost 13 years
    @Peter: That's partial application, not currying. And neither is specific to collection operations.
  • Vishy
    Vishy almost 13 years
    @missingfaktor, My point is; not to get hung up on a specific feature but take a step back and look at the wider problem and there is very likely to be a simple solution.
  • missingfaktor
    missingfaktor almost 13 years
    @Peter: If you want to question the point of the question, you should post your remark as a comment, and not as an answer. (IMHO)
  • Vishy
    Vishy almost 13 years
    @missingfaktor, You are right, but in my case I wanted to give what I believe is the answer in Java to the real problem which is to use the techniques which work well in Java.
  • Andreas Dolk
    Andreas Dolk almost 13 years
    Now that I've finished my example (developed from scratch) it turns out, that the only difference to missingcodes answer is that I don't use anonymous classes ;)
  • Andreas Dolk
    Andreas Dolk almost 13 years
    @missingfaktor - mea culpa ;)
  • Matthias Braun
    Matthias Braun about 10 years
    This answer is outdated since the release of Java 8. See Rogério's answer for a more concise way.
  • Anthony Fammartino
    Anthony Fammartino about 9 years
    I'm impressed with Java 8, but Clojure is a compelling platform beyond functional language features. Clojure offers highly efficient, immutable data structures and sophisticated concurrency techniques such as software-transactional memory.
  • Korny
    Korny about 9 years
    Thanks for the solution, not so much for the language dig :) Weaker IDE support is an issue, but tooling/libraries is not clear cut - having gone back to Java 8 after Clojure, I'm really missing tools midje, libraries like core.async, and language features like macros and easy functional syntax. The currying example in clojure: (def adder5 (partial + 5)) (prn (adder5 4)) (prn adder5 6)
  • Rogério
    Rogério about 9 years
    Clojure may be a great language, but the problem is that it's just too "alien" for the majority of Java developers that are only used to conventional C-style syntax; it's very hard to see a significant migration to Clojure (or any other alternative JVM language) in the future, specially considering that several such languages already exist for many years and it hasn't happened (the same phenomenon occurs in the .NET world, where languages like F# remain marginal).
  • zinking
    zinking over 8 years
    which is still ugly and probably just for fun
  • M4ks
    M4ks almost 8 years
    I have to downvote, because it shows simple case. Try one which from String makes your own class which then converts to some other class, and compare the amount of code
  • Rogério
    Rogério almost 8 years
    @M4ks The question is only whether Java supports currying or not, it's not about the amount of code when compared to other languages.
  • Jose Romero
    Jose Romero over 7 years
    Actually there are plenty of reasons not to use Java: Less code legibility, primitives' mess, no pattern matching, no case classes, no real closures, verbosity, no default parameters, no type inference, no implicit values, not immutable by default, and immutable is normally by reference and not by structure, no good concurrency model, no literal definition of tuples, etc, etc. If you can choose, go for Scala. If you can't, well Java 8 is not thaaaaaaaat bad.
  • Rogério
    Rogério over 7 years
    If I could choose (and face it, the reality is that we almost always have little or no say in such matters) I would go with Kotlin, a much more developer-friendly language than "academic"-friendly Scala (or at least that's my perception).
  • Lebecca
    Lebecca about 4 years
    IMO, this is what really called currying in the Curry.curryn source code.