Java 支持柯里化吗?

发布于 2024-11-09 12:22:04 字数 57 浏览 4 评论 0原文

我想知道是否有任何方法可以在 Java 中实现这一点。我认为如果没有对闭包的原生支持,这是不可能的。

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

貪欢 2024-11-16 12:22:04

Java 8(2014 年 3 月 18 日发布)确实支持柯里化。 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 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.

够钟 2024-11-16 12:22:04

在 Java 中,柯里化和部分应用是绝对可能的,但所需的代码量可能会让您望而却步。


一些代码来演示 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 这里是上面 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 $ simpleAdd (5, 4)

  -- Demonstrating curriedAdd
  print $ curriedAdd 5 4

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

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
谁的年少不轻狂 2024-11-16 12:22:04

使用 Java 8 进行柯里化有很多选项。函数类型 Javaslang 和 jOOλ 都提供开箱即用的柯里化(我认为这是 JDK 中的一个疏忽),并且 独眼巨人 函数模块 有一组用于 Currying JDK 函数和方法引用的静态方法。例如,

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

消费者也可以使用“柯里化”。例如,要返回一个具有 3 个参数的方法,其中 2 个参数已应用,我们会执行类似的操作

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

Javadoc

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

舟遥客 2024-11-16 12:22:04

编辑:从 2014 年和 Java 8 开始,Java 中的函数式编程现在不仅是可能的,而且也不难看(我敢说很漂亮)。例如,请参阅Rogerio 的回答

旧答案:

如果您要使用函数式编程技术,Java 并不是最佳选择。正如 Missingfaktor 所写,您将不得不编写大量代码才能实现您想要的目标。

另一方面,您并不局限于 JVM 上的 Java - 您可以使用 ScalaClojure 是函数式语言(事实上,Scala 既是函数式语言,又是面向对象语言)。

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).

人事已非 2024-11-16 12:22:04

柯里化需要返回一个函数。这对于 java 来说是不可能的(没有函数指针),但我们可以定义并返回一个包含函数方法的类型:

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

现在让我们柯里化一个简单的除法。我们需要一个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;
  }
}

和一个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);
  }

现在我们可以进行柯里化除法:

DivideFunction divide = new DivideFunction();
double result = divide.f(2.).f(1.);  // calculates f(1,2) = 0.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
生活了然无味 2024-11-16 12:22:04

可以使用 Java 7 MethodHandles 来模拟柯里化:
http://www.tutorials.de/threads/java- 7-currying-mit-methodhandles.392397/

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class MethodHandleCurryingExample {
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle sum = lookup.findStatic(Integer.class, "sum", MethodType.methodType(int.class, new Class[]{int.class, int.class}));
        //Currying
        MethodHandle plus1 = MethodHandles.insertArguments(sum,0,1);
        int result = (int) plus1.invokeExact(2);
        System.out.println(result); // Output: 3
    }
}

One can emulate currying with Java 7 MethodHandles:
http://www.tutorials.de/threads/java-7-currying-mit-methodhandles.392397/

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class MethodHandleCurryingExample {
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle sum = lookup.findStatic(Integer.class, "sum", MethodType.methodType(int.class, new Class[]{int.class, int.class}));
        //Currying
        MethodHandle plus1 = MethodHandles.insertArguments(sum,0,1);
        int result = (int) plus1.invokeExact(2);
        System.out.println(result); // Output: 3
    }
}
醉城メ夜风 2024-11-16 12:22:04

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

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 是一个返回另一个函数的柯里化函数,这可用于存储时参数的部分应用柯里化中,它本身就是一个函数。当我们将其打印到屏幕上时,现在会完全应用这一点。

此外,稍后您可以看到如何以 JS 风格使用它,如下所示

curriedAdd.apply(1).apply(2) //in Java
//is equivalent to 
curriedAdd(1)(2) // in JS

Yes, see the code example for yourself:

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

    }

}

This is simple example with curriedAdd being a curried function which returns another function, and this can be used for partial application of parameters as stored in curried which is a function in itself. This is now later applied fully when we print it on screen.

Moreover, later you can see how you can use it in kind of JS style as

curriedAdd.apply(1).apply(2) //in Java
//is equivalent to 
curriedAdd(1)(2) // in JS
注定孤独终老 2024-11-16 12:22:04

嗯,Scala、Clojure 或 Haskell(或任何其他函数式编程语言...)绝对是用于柯里化和其他函数式技巧的语言。

话虽如此,当然可以使用 Java 进行柯里化,而无需人们所期望的大量样板文件(嗯,必须明确类型,但会造成很大伤害 - 只需看一下柯里化示例即可; -))。

下面的测试展示了这两种情况,将Function3柯里化Function1 =>中。函数1 => Function1

@Test
public void shouldCurryFunction() throws Exception {
  // given
  Function3<Integer, Integer, Integer, Integer> func = (a, b, c) -> a + b + c;

  // when
  Function<Integer, Function<Integer, Function<Integer, Integer>>> cur = curried(func);

  // then
  Function<Integer, Function<Integer, Integer>> step1 = cur.apply(1);
  Function<Integer, Integer> step2 = step1.apply(2);
  Integer result = step2.apply(3);

  assertThat(result).isEqualTo(6);
}

以及部分应用,尽管在​​本例中它并不是真正的类型安全:

@Test
public void shouldCurryOneArgument() throws Exception {
  // given
  Function3<Integer, Integer, Integer, Integer> adding = (a, b, c) -> a + b + c;

  // when
  Function2<Integer, Integer, Integer> curried = applyPartial(adding, _, _, put(1));

  // then
  Integer got = curried.apply(0, 0);
  assertThat(got).isEqualTo(1);
}

这取自我刚刚在明天一小时内的 JavaOne 之前为了好玩而实现的概念验证”因为我很无聊”;-) 代码可以在这里找到:https://github.com/ktoso/jcurry

总体思路可以扩展为 FunctionN => FunctionM,相对容易,尽管“真正的类型安全”对于部分应用程序示例来说仍然是一个问题,并且柯里化示例将需要 jcurry 中的大量样板代码,但它是可行的。

总而言之,这是可行的,但在 Scala 中它是开箱即用的;-)

Well, Scala, Clojure or Haskell (or any other functional programming language...) are definitely THE languages to use for currying and other functional tricks.

Having that said is certainly possible to curry with Java without the super amounts of boilerplate one might expect (well, having to be explicit about the types hurts a lot though - just take a look at the curried example ;-)).

The tests bellow showcase both, currying a Function3 into Function1 => Function1 => Function1:

@Test
public void shouldCurryFunction() throws Exception {
  // given
  Function3<Integer, Integer, Integer, Integer> func = (a, b, c) -> a + b + c;

  // when
  Function<Integer, Function<Integer, Function<Integer, Integer>>> cur = curried(func);

  // then
  Function<Integer, Function<Integer, Integer>> step1 = cur.apply(1);
  Function<Integer, Integer> step2 = step1.apply(2);
  Integer result = step2.apply(3);

  assertThat(result).isEqualTo(6);
}

as well as partial application, although it's not really typesafe in this example:

@Test
public void shouldCurryOneArgument() throws Exception {
  // given
  Function3<Integer, Integer, Integer, Integer> adding = (a, b, c) -> a + b + c;

  // when
  Function2<Integer, Integer, Integer> curried = applyPartial(adding, _, _, put(1));

  // then
  Integer got = curried.apply(0, 0);
  assertThat(got).isEqualTo(1);
}

This is taken from a Proof Of Concept I've just implemented for fun before JavaOne tomorrow in an hour "because I was bored" ;-) The code is available here: https://github.com/ktoso/jcurry

The general idea could be expanded to FunctionN => FunctionM, relatively easily, though "real typesafety" remains a problem for the partia application example and the currying example would need a hell lot of boilerplaty code in jcurry, but it's doable.

All in all, it's doable, yet in Scala it's out of the box ;-)

如梦初醒的夏天 2024-11-16 12:22:04

Java 8 的另一种可能性:

BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;

Function<Integer, Integer> increment = y -> add.apply(1, y);
assert increment.apply(5) == 6;

您还可以定义如下所示的实用方法:

static <A1, A2, R> Function<A2, R> curry(BiFunction<A1, A2, R> f, A1 a1) {
    return a2 -> f.apply(a1, a2);
}

这为您提供了一种可以说更易读的语法:

Function<Integer, Integer> increment = curry(add, 1);
assert increment.apply(5) == 6;

One more take on the Java 8 possibilities:

BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;

Function<Integer, Integer> increment = y -> add.apply(1, y);
assert increment.apply(5) == 6;

You can also define utility methods like this one:

static <A1, A2, R> Function<A2, R> curry(BiFunction<A1, A2, R> f, A1 a1) {
    return a2 -> f.apply(a1, a2);
}

Which gives you an arguably more readable syntax:

Function<Integer, Integer> increment = curry(add, 1);
assert increment.apply(5) == 6;
薆情海 2024-11-16 12:22:04

在 Java 中柯里化方法总是可能的,但它不以标准方式支持它。尝试实现这一点很复杂,并且使代码非常难以阅读。 Java 不是适合此目的的语言。

Currying a method is always possible in Java, but it does not support it in a standard way. Trying to achieve this is complicated and makes the code pretty unreadable. Java is not the appropriate language for this.

情深如许 2024-11-16 12:22:04

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

,那么你可以通过这种方式实现柯里化

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

An another choice is here for 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);
}

then you could achieve currying by this way

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();
触ぅ动初心 2024-11-16 12:22:04

虽然您可以在 Java 中进行柯里化,但它很丑陋(因为它不受支持)。在 Java 中,使用普通循环和简单表达式更简单、更快。如果您发布一个使用柯里化的示例,我们可以建议执行相同操作的替代方案。

While you can do Currying in Java, it is ugly (because its not supported) In Java is it simpler and faster to use plain loops and simple expressions. If you post an example of where you would use currying, we can suggest alternatives which do the same thing.

十秒萌定你 2024-11-16 12:22:04

在 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
      }
    }

The advantage of using Currying in Java 8 is that it lets you define high order functions and then pass a first order function and function arguments in a chained, elegant way.

Here is an example for Calculus, the derivative function.

  1. Lets define the derivative function approximation as (f(x+h)-f(x))/h. This will be the high order function
  2. Let's calculate the derivative of 2 different functions, 1/x, and the standardized gaussian distribution

1

    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
      }
    }
时光是把杀猪刀 2024-11-16 12:22:04

这是一个用于 Java 中柯里化和部分应用的库:

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

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

更多详细信息请参见 README 文件

This is a library for currying and partial application in Java :

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

It also supports destructuring Tuples and Map.Entry into method parameters, like for example passing a Map.Entry to a method that takes 2 parameters, so the Entry.getKey() will go to the first parameter, and the Entry.getValue() will go for the second parameter

More details in the README file

万劫不复 2024-11-16 12:22:04

是的,我同意@Jérôme 的观点,Java 8 中的curring 不像Scala 或其他函数式编程语言那样以标准方式支持。

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

Yes, I agree with @Jérôme, curring in Java 8 is not supported in a standard way like in Scala or other functional programming languages.

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");
  }
}
陈年往事 2024-11-16 12:22:04

虽然所有其他答案都集中在特定示例上,但我仍然想提供一个通用解决方案,将二进制函数转换为柯里化函数。

private static <A, B, C> Function<A, Function<B, C>> Curry(BiFunction<A, B, C> f) {
    return a -> b -> f.apply(a, b);
}

While all the other answers focus on specific examples, I still wanted to provide a general solution to turn binary functions into curried ones.

private static <A, B, C> Function<A, Function<B, C>> Curry(BiFunction<A, B, C> f) {
    return a -> b -> f.apply(a, b);
}
亢潮 2024-11-16 12:22:04
// Usage of `BiFnCurry.curry` defined below
someStream.map(curry(this::someBiFunction).apply(1stBiFnParam))
// someBiFunction is Function<1stBiFnParam, 2ndBiFnParam, R>
// curry(this::someBiFunction).apply(1stBiFnParam) returns Function<2ndBiFnParam, R>

public class BiFnCurry {
    public static <T1, T2, R> Function<T1, Function<T2, R>> curry(BiFunction<T1, T2, R> biFn) {
        return t1 -> (t2 -> biFn.apply(t1, t2));
    }
}
// Usage of `BiFnCurry.curry` defined below
someStream.map(curry(this::someBiFunction).apply(1stBiFnParam))
// someBiFunction is Function<1stBiFnParam, 2ndBiFnParam, R>
// curry(this::someBiFunction).apply(1stBiFnParam) returns Function<2ndBiFnParam, R>

public class BiFnCurry {
    public static <T1, T2, R> Function<T1, Function<T2, R>> curry(BiFunction<T1, T2, R> biFn) {
        return t1 -> (t2 -> biFn.apply(t1, t2));
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文