- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
因此,在稍微接触了 Java 泛型之后,为了更深入地了解它们的功能,我决定尝试实现函数式程序员熟悉的组合函数的柯里化(Currying)版本。 Compose 具有类型(在函数式语言中)(b -> c) -> (a -> b) -> (a -> c)
。执行柯里化(Currying)算术函数并不太难,因为它们只是多态的,但 compose 是一个高阶函数,事实证明它对我理解 Java 中的泛型很费力。
这是我目前创建的实现:
public class Currying {
public static void main(String[] argv){
// Basic usage of currying
System.out.println(add().ap(3).ap(4));
// Next, lets try (3 * 4) + 2
// First lets create the (+2) function...
Fn<Integer, Integer> plus2 = add().ap(2);
// next, the times 3 function
Fn<Integer, Integer> times3 = mult().ap(3);
// now we compose them into a multiply by 2 and add 3 function
Fn<Integer, Integer> times3plus2 = compose().ap(plus2).ap(times3);
// now we can put in the final argument and print the result
// without compose:
System.out.println(plus2.ap(times3.ap(4)));
// with compose:
System.out.println(times3plus2.ap(new Integer(4)));
}
public static <A,B,C>
Fn<Fn<B,C>, // (b -> c) -> -- f
Fn<Fn<A,B>, // (a -> b) -> -- g
Fn<A,C>>> // (a -> c)
compose(){
return new Fn<Fn<B,C>,
Fn<Fn<A,B>,
Fn<A,C>>> () {
public Fn<Fn<A,B>,
Fn<A,C>> ap(final Fn<B,C> f){
return new Fn<Fn<A,B>,
Fn<A,C>>() {
public Fn<A,C> ap(final Fn<A,B> g){
return new Fn<A,C>(){
public C ap(final A a){
return f.ap(g.ap(a));
}
};
}
};
}
};
}
// curried addition
public static Fn<Integer, Fn<Integer, Integer>> add(){
return new Fn<Integer, Fn<Integer, Integer>>(){
public Fn<Integer,Integer> ap(final Integer a) {
return new Fn<Integer, Integer>() {
public Integer ap(final Integer b){
return a + b;
}
};
}
};
}
// curried multiplication
public static Fn<Integer, Fn<Integer, Integer>> mult(){
return new Fn<Integer, Fn<Integer, Integer>>(){
public Fn<Integer,Integer> ap(final Integer a) {
return new Fn<Integer, Integer>() {
public Integer ap(final Integer b){
return a * b;
}
};
}
};
}
}
interface Fn<A, B> {
public B ap(final A a);
}
add、mult 和 compose 的实现都编译得很好,但我发现自己在实际使用 compose 时遇到了问题。我在第 12 行收到以下错误(在 main 中第一次使用 compose):
Currying.java:12: ap(Fn<java.lang.Object,java.lang.Object>) in
Fn<Fn<java.lang.Object,java.lang.Object>,Fn<Fn<java.lang.Object,java.lang.Object>,Fn<java.lang.Object,java.lang.Object>>>
cannot be applied to (Fn<java.lang.Integer,java.lang.Integer>)
Fn<Integer,Integer> times3plus2 = compose().ap(plus2).ap(times3);
我假设这个错误是因为泛型类型是不变的,但我不确定如何解决这个问题。据我所知,在某些情况下可以使用通配符类型变量来减轻不变性,但我不确定在这里如何使用它,甚至不确定它是否有用。
免责声明:我无意在任何实际项目中编写这样的代码。这是一种有趣的“可以做到”的事情。此外,我违反了标准的 Java 惯例,使变量名变得简短,否则这个示例将变成甚至难以理解的文本墙。
最佳答案
这里的基本问题是,在对 compose()
的原始调用中,编译器无法推断 A、B 和 C 的绑定(bind),因此它假设它们都成为对象。您可以通过明确指定类型绑定(bind)来修复它:
Fn<Integer, Integer> times3plus2 =
Currying.<Integer, Integer, Integer>compose().ap(plus2).ap(times3);
当然,您会失去类型推断带来的清晰度。如果您需要类型推断,您可以定义一些中间类来进行推断:
public static ComposeStart compose() {
return new ComposeStart();
}
class ComposeStart {
public <B,C> ComposeContinuation<B,C> ap(Fn<B,C> f) {
return new ComposeContinuation<B, C>(f);
}
}
class ComposeContinuation<B, C> {
private final Fn<B,C> f;
ComposeContinuation(Fn<B,C> f) {
this.f = f;
}
public <A> Fn<A,C> ap(final Fn<A,B> g) {
return new Fn<A,C>() {
public C ap(A a) {
return f.ap(g.ap(a));
}
};
}
}
但是,柯里化(Currying)的中间步骤不再是 Fn
。
关于java - 滥用泛型在 Java 中实现柯里化(Currying)组合函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8913900/
我是一名优秀的程序员,十分优秀!