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)}
什么区别?
虽然两个操作都输出了一个函数,但是这个例子使得差异非常明显:
f()
并生成一个"中间"函数f'()
,该函数f()
与已修复的某些参数相同.当您最终填写其余参数时,您将评估原始参数f()
.f()
,g()
并创建一个完全不同的功能g(f())
.举一个简单的例子:f(x,y) = x+y
,在哪里x
和y
是整数.此函数的任何数量和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子集以及如何实现.
我想通过@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中受益呢?
当您需要在多个级别参数化函数时,它非常有用.例如,假设我们有几个集合,每个集合代表不同的类别,我们希望从每个类别中检索特定元素.下面是一个简单的例子,给出两个集合,代表拼写的数字,分类为ones
和tens
.示例:
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
检索80
的tens
集合.
同样的逻辑适用于currying.apply("Ones").apply(2))
.