Java支持Currying吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java支持Currying吗?相关的知识,希望对你有一定的参考价值。

我想知道是否有任何方法可以在Java中提取它。我认为没有原生支持闭包是不可能的。

答案

Java 8(2014年3月18日发布)确实支持currying。在the answer by missingfaktor中发布的示例Java代码可以重写为:

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

......非常好。就个人而言,在Java 8可用的情况下,我认为没有理由使用替代JVM语言,例如Scala或Clojure。当然,它们提供其他语言功能,但这还不足以证明过渡成本和较弱的IDE /工具/库支持IMO。

另一答案

另一个选择是Java 6+

abstract class CurFun<Out> {

    private Out result;
    private boolean ready = false;

    public boolean isReady() {
        return ready;
    }

    public Out getResult() {
        return result;
    }

    protected void setResult(Out result) {
        if (isReady()) {
            return;
        }

        ready = true;
        this.result = result;
    }

    protected CurFun<Out> getReadyCurFun() {
        final Out finalResult = getResult();
        return new CurFun<Out>() {
            @Override
            public boolean isReady() {
                return true;
            }
            @Override
            protected CurFun<Out> apply(Object value) {
                return getReadyCurFun();
            }
            @Override
            public Out getResult() {
                return finalResult;
            }
        };
    }

    protected abstract CurFun<Out> apply(final Object value);
}

然后你可以通过这种方式实现currying

CurFun<String> curFun = new CurFun<String>() {
    @Override
    protected CurFun<String> apply(final Object value1) {
        return new CurFun<String>() {
            @Override
            protected CurFun<String> apply(final Object value2) {
                return new CurFun<String>() {
                    @Override
                    protected CurFun<String> apply(Object value3) {
                        setResult(String.format("%s%s%s", value1, value2, value3));
//                        return null;
                        return getReadyCurFun();
                    }
                };
            }
        };
    }
};

CurFun<String> recur = curFun.apply("1");
CurFun<String> next = recur;
int i = 2;
while(next != null && (! next.isReady())) {
    recur = next;
    next = recur.apply(""+i);
    i++;
}

// The result would be "123"
String result = recur.getResult();
另一答案

是的,请亲自查看代码示例:

import java.util.function.Function;

public class Currying {

    private static Function<Integer, Function<Integer,Integer>> curriedAdd = a -> b -> a+b ;

    public static void main(String[] args) {

        //see partial application of parameters
        Function<Integer,Integer> curried = curriedAdd.apply(5);
        //This partial applied function can be later used as
        System.out.println("ans of curried add by partial application: "+ curried.apply(6));
        // ans is 11

        //JS example of curriedAdd(1)(3)
        System.out.println("ans of curried add: "+ curriedAdd.apply(1).apply(3));
        // ans is 4

    }

}

这是一个简单的例子,curriedAdd是一个curried函数,返回另一个函数,这可以用于部分应用存储在curried中的参数,这本身就是一个函数。现在,我们将在屏幕上打印时完全应用。

而且,稍后你可以看到如何在JS风格中使用它

curriedAdd.apply(1).apply(2) //in Java
//is equivalent to 
curriedAdd(1)(2) // in JS
另一答案

虽然你可以在Java中使用Currying,但它很难看(因为它不受支持)在Java中,使用普通循环和简单表达式更简单,更快捷。如果您发布一个使用currying的示例,我们可以建议做同样事情的替代方案。

另一答案

这是一个用于Java中的currying和部分应用程序的库:

https://github.com/Ahmed-Adel-Ismail/J-Curry

它还支持将Tuples和Map.Entry解构为方法参数,例如将Map.Entry传递给带有2个参数的方法,因此Entry.getKey()将转到第一个参数,并且Entry.getValue()将去第二个参数

README文件中的更多详细信息

另一答案

在Java 8中使用Currying的优点是它允许您定义高阶函数,然后以链式,优雅的方式传递一阶函数和函数参数。

这是推导函数微积分的一个例子。

  1. 让我们将导数函数近似定义为(f(x + h)-f(x))/ h。这将是高阶函数
  2. 让我们计算2个不同函数的导数,1 / x和标准化高斯分布

    package math;

    import static java.lang.Math.*;
    import java.util.Optional;
    import java.util.function.*;

    public class UnivarDerivative
    {
      interface Approximation extends Function<Function<Double,Double>, 
      Function<Double,UnaryOperator<Double>>> {}
      public static void main(String[] args)
      {
        Approximation derivative = f->h->x->(f.apply(x+h)-f.apply(x))/h;
        double h=0.00001f;
        Optional<Double> d1=Optional.of(derivative.apply(x->1/x).apply(h).apply(1.0)); 
        Optional<Double> d2=Optional.of(
        derivative.apply(x->(1/sqrt(2*PI))*exp(-0.5*pow(x,2))).apply(h).apply(-0.00001));
        d1.ifPresent(System.out::println); //prints -0.9999900000988401
        d2.ifPresent(System.out::println); //prints 1.994710003159016E-6
      }
    }
另一答案

是的,我同意@Jérôme,在Scala或其他函数式编程语言中,标准方式不支持Java 8中的限制。

public final class Currying {
  private static final Function<String, Consumer<String>> MAILER = (String ipAddress) -> (String message) -> {
    System.out.println(message + ":" + ipAddress );
  };
  //Currying
  private static final Consumer<String> LOCAL_MAILER =  MAILER.apply("127.0.0.1");

  public static void main(String[] args) {
      MAILER.apply("127.1.1.2").accept("Hello !!!!");
      LOCAL_MAILER.accept("Hello");
  }
}
另一答案

在Java中绝对可以使用Currying和部分应用程序,但是所需的代码量可能会让您失望。


一些代码用于演示Java中的currying和部分应用:

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是上面Java代码的Haskell等价物:

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

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

main = do
  -- Demonstrating simpleAdd
  print $

以上是关于Java支持Currying吗?的主要内容,如果未能解决你的问题,请参考以下文章

java8:lambda级联表达式(Cascading)或柯里化(Currying)原理简化详解

java8:lambda级联表达式(Cascading)或柯里化(Currying)原理简化详解

架构丰富的代码片段也应该用于产品列表吗?

Swift函数柯里化(Currying)简谈

javascript 为功能代码编写的动态currying函数(没有`this`上下文)。

Currying 及应用