Java 8函数样式编程currying和Functions Composition之间的区别是什么

Mu *_* Pi 5 java lambda functional-programming currying java-8

我对函数式编程的世界很陌生.最近我学习了关于currying和方法组合的新功能样式编程.理解使用java的函数式编程的真正本质是非常困难的,现在我有几个问题,但是,在问这些问题之前,我在python上尝试了同样的东西,现在对一些核心概念有点熟悉.

1.在java中如何Currying和方法组成不同实际上我没有看到任何差别,特别是在阅读本文之后https://dzone.com/articles/higher-order-functions

2.作为一个程序员(从我的java编程角度来看)为什么我更喜欢currying.例如,为什么我会这样做, f(x){ return g(y) }而不是它有f(x,y){ return x(y)}什么区别?

biz*_*lop 8

虽然两个操作都输出了一个函数,但是这个例子使得差异非常明显:

  1. Currying采用单个函数f()并生成一个"中间"函数f'(),该函数f()与已修复的某些参数相同.当您最终填写其余参数时,您将评估原始参数f().
  2. 虽然构图将采用两个功能f(),g()并创建一个完全不同的功能g(f()).

举一个简单的例子:f(x,y) = x+y,在哪里xy是整数.此函数的任何数量和currying组合都不会导致函数返回非整数结果.但是g(x) = x/2要把它组合起来,你得到的g(f(x,y)) = (x+y)/2,当然会很高兴地返回非整数.

你为什么要使用currying?

例如,Java实例方法是一个非常相似的过程的结果.实例方法与静态方法的不同之处在于它们有一个额外的隐藏参数this.当你说new Foo(),基本上你将这个隐藏的参数绑定到新创建的Foo对象.因此,不必调用函数void bar(Foo this, int x),您可以将其称为void bar(int x),第一个参数已经固定.(顺便说一下,void bar(Foo this, int x)实际上是完全有效的Java语法,我们几乎从不使用它.)

这并非完全是巧合,因为纯函数式语言只能具有其输出仅依赖于其输入的函数(与OO语言相反,其中方法的输出也可以取决于该方法所属的对象的内部状态. .)

作为一般建议,如果你想学习函数式编程的本质,最好不要用Java来实现.甚至不是来自Scala.尝试从像Haskell这样的纯函数语言中学习它,然后您可以回到Java并更好地理解在其中实现的FP子集以及如何实现.


fg7*_*8nc 6

我想通过@biziclop为一些非常好的解释添加一些代码:

函数Java中的currying示例:

BiFunction<Integer, Integer, IntFunction<Integer>> currying = (x, y) -> z -> x * y / z;
    System.out.println(currying.apply(5, 6).apply(2)); // 15
Run Code Online (Sandbox Code Playgroud)

如您所见,lambda已参数化.在这个例子中,我们假设将5乘以6,然后除以2.

首先apply(5)调用和变量x获取值5和函数变为5 * y / z

然后apply(6)调用并且变量'y'得到值'6'并且函数变为5 * 6 / z

然后apply(2)调用并且变量'z'得到值'2'并且函数变为5 * 6 / 2

因为你可以使用currying这种方式在Java中几乎没用.Currying在纯函数式语言中很有用,其中函数仅限于单个参数,并且它们受益于currying,它会转换带有多个参数的函数,因此可以使用单个参数调用多次调用它.

那你怎么能从Java的currying中受益呢?

当您需要在多个级别参数化函数时,它非常有用.例如,假设我们有几个集合,每个集合代表不同的类别,我们希望从每个类别中检索特定元素.下面是一个简单的例子,给出两个集合,代表拼写的数字,分类为onestens.示例:

public class Currying {

    private static List<String> ones = 
           Arrays.asList("Zero", "One", "Two", "Three", "Four", 
                                 "Five", "Six", "Seven", "Eight", "Nine");
    private static List<String> tens =
           Arrays.asList("Zero", "Ten", "Twenty", "Thirty", "Forty",
                                "Fifty", "Sixty", "Seventy", "Eighty", "Ninety");

    public static Function<String, Function<Integer, String>> getNumbers() {
        return units -> number -> {
                        return units == "Ones" ? ones.get(number % 10) 
                                               : tens.get(number % 10);
                                  };
    }

    public static void main(String[] args) {
        Function<String, Function<Integer, String>> currying = getNumbers();
        System.out.println(currying.apply("Tens").apply(8)); // 80
        System.out.println(currying.apply("Ones").apply(2)); // 2
    }

}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中功能currying返回另一个功能 currying.apply("Ones").apply(2));

首先apply("Tens")调用,变量units变为Tens

然后apply(2)调用和可变number变得8检索80tens集合.

同样的逻辑适用于currying.apply("Ones").apply(2)).

  • 美丽的例子.万分感谢. (3认同)