Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
滥用泛型在Java中实现curried合成函数_Java_Generics_Functional Programming_Currying - Fatal编程技术网

滥用泛型在Java中实现curried合成函数

滥用泛型在Java中实现curried合成函数,java,generics,functional-programming,currying,Java,Generics,Functional Programming,Currying,因此,在对Java泛型进行了一些研究之后,为了更深入地了解它们的功能,我决定尝试实现函数式程序员熟悉的组合函数的curried版本。Compose的类型是(在函数式语言中)(b->c)->(a->b)->(a->c)。编写算术函数并不难,因为它们只是多态的,但compose是一个更高阶的函数,这对我理解Java中的泛型来说是一个累赘 以下是我迄今为止创建的实现: public class Currying { public static void main(String[] argv){

因此,在对Java泛型进行了一些研究之后,为了更深入地了解它们的功能,我决定尝试实现函数式程序员熟悉的组合函数的curried版本。Compose的类型是(在函数式语言中)
(b->c)->(a->b)->(a->c)
。编写算术函数并不难,因为它们只是多态的,但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);
}
公共类咖喱{
公共静态void main(字符串[]argv){
//咖喱的基本用法
System.out.println(add().ap(3.ap(4));
//接下来,让我们试试(3*4)+2
//首先让我们创建(+2)函数。。。
Fn plus2=add().ap(2);
//接下来是times 3函数
Fn times3=mult().ap(3);
//现在我们把它们组合成一个乘2加3的函数
Fn times3plus2=compose().ap(plus2).ap(times3);
//现在我们可以输入最后一个参数并打印结果
//无需撰写:
System.out.println(plus2.ap(times3.ap(4));
//与撰写:
System.out.println(times3plus2.ap(新整数(4));
}
公共静电
Fn c)->--f
Fn b)->--g
Fn>>/(a->c)
撰写(){
返回新的Fn(){
公共Fn ap(最终Fn f){
返回新的Fn(){
公共Fn ap(最终Fn g){
返回新的Fn(){
公共C ap(最终A){
返回f.ap(g.ap(a));
}
};
}
};
}
};
}
//咖喱加成
公共静态Fn add(){
返回新的Fn(){
公共Fn ap(最终整数a){
返回新的Fn(){
公共整数ap(最终整数b){
返回a+b;
}
};
}
};
}
//咖喱乘法
公共静态Fn mult(){
返回新的Fn(){
公共Fn ap(最终整数a){
返回新的Fn(){
公共整数ap(最终整数b){
返回a*b;
}
};
}
};
}
}
接口Fn{
公共B ap(最终A);
}
add、mult和compose的实现都可以很好地编译,但我发现自己在实际使用compose时遇到了一个问题。第12行出现以下错误(在main中首次使用compose):

java:12:ap(Fn)in Fn 无法应用于(Fn) Fn times3plus2=compose().ap(plus2).ap(times3); 我假设这个错误是因为泛型类型是不变的,但我不确定如何解决这个问题。据我所知,通配符类型的变量在某些情况下可以用来减轻不变性,但我不确定如何在这里使用它,甚至不知道它是否有用


免责声明:我无意在任何实际项目中编写这样的代码。这是一件有趣的“能做到”的事情。此外,我不顾标准Java实践,简化了变量名,因为否则这个示例将变得更加难以理解。

这里的基本问题是,在最初调用
compose()
时,编译器无法推断A、B和C的绑定,所以它假设它们都是对象。可以通过显式指定类型绑定来修复它:

Fn<Integer, Integer> times3plus2 = 
    Currying.<Integer, Integer, Integer>compose().ap(plus2).ap(times3);
Fn times3plus2=
Currying.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));
            }
        };
    }
}
public static ComposeStart compose(){
返回新的ComposeStart();
}
类ComposeStart{
公共合成继续ap(Fn f){
返回新组件继续(f);
}
}
类复合继续{
私人最终Fn f;
复合连续性(Fn f){
这个。f=f;
}
公共Fn ap(最终Fn g){
返回新的Fn(){
公共行政助理(甲){
返回f.ap(g.ap(a));
}
};
}
}

然而,接下来的中间步骤不再是
Fn
s.

多亏了Russell Zahniser的洞察力,我没有给Java提供足够的信息,所以我稍微改变了布局,以便我们实例化一个“Composer”对象,并填入适当的类型变量。以下是我目前的工作方案:

interface Fn<A, B> {
  public B ap(final A a);
}

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 = new Composer<Integer,Integer,Integer>()
      .compose().ap(plus2).ap(times3);
    // without compose
    System.out.println(plus2.ap(times3.ap(4)));
    // with compose
    System.out.println(times3plus2.ap(4));
  }

  static class Composer<A,B,C> { 
    public
      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));
                }
              };
            }
          };
        }
      };
    }
  }

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

  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;
          }
        };
      }
    };
  }
}
接口Fn{
公共B ap(最终A);
}
公共课咖喱{
公共静态void main(字符串[]argv){
//咖喱的基本用法
System.out.println(add().ap(3.ap(4));
//接下来,让我们试试(3*4)+2
//首先让我们创建(+2)函数。。。
Fn plus2=add().ap(2);
//接下来是times 3函数
Fn times3=mult().ap(3);
//现在我们把它们组合成一个乘2加3的函数
Fn times3plus2=新作曲家()
.compose().ap(plus2).ap(times3);
//不假思索
System.out.println(plus2.ap(times3.ap(4));
//用作曲
System.out.println(times3plus2.ap(4));
}
静态类生成器{
公众的
Fn c)->--f
Fn b)->--g
Fn>>/(a->c)
撰写(){
返回新的Fn(){
公共Fn ap(最终Fn f){
返回新的Fn(){
公共Fn ap(最终Fn g){
返回新的Fn(){
公共C ap(最终A){
返回f.ap(g.ap(a));
}
};
}
};
}
};
}
}
公共静态Fn add(){
返回新的Fn(){
公共Fn ap(最终整数a){
返回新的Fn(){
公共整数ap(最终整数b){
返回a+b;
}
};
}
};
}
公共静态Fn mult(){
返回新的Fn(){
公共Fn ap(最终整数a){
返回新的Fn(){
公共整数ap(最终整数b){
interface Fn<A, B> {
  public B ap(final A a);
}

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 = new Composer<Integer,Integer,Integer>()
      .compose().ap(plus2).ap(times3);
    // without compose
    System.out.println(plus2.ap(times3.ap(4)));
    // with compose
    System.out.println(times3plus2.ap(4));
  }

  static class Composer<A,B,C> { 
    public
      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));
                }
              };
            }
          };
        }
      };
    }
  }

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

  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;
          }
        };
      }
    };
  }
}
public static final <X, Y> Chainer<X, Y> chain(
        final Function<X, Y> primary
) {
    return new Chainer<X, Y>(primary);
}

private static final class FunctionChain<IN, OUT> implements Function<IN, OUT> {

    @SuppressWarnings("rawtypes")
    private final List<Function> chain =  new LinkedList<Function>();

    private FunctionChain(@SuppressWarnings("rawtypes") final List<Function> chain) {
        this.chain.addAll(chain);
    }

    @SuppressWarnings("unchecked")
    @Override
    public OUT apply(final IN in) {
        Object ret = in;
        for (final Function<Object, Object> f : chain) {
            ret = f.apply(ret);
        }
        return (OUT) ret;
    }
}

public static final class Chainer<IN, OUT> {
    @SuppressWarnings("rawtypes")
    private final LinkedList<Function> functions = new LinkedList<Function>();

    @SuppressWarnings("unchecked")
    private Chainer(@SuppressWarnings("rawtypes") final Function func) {
        then(func);
    }

    @SuppressWarnings("unchecked")
    public <OUT2> Chainer<IN, OUT2> then(final Function<OUT, OUT2> func) {
        if (func instanceof FunctionChain) {
            functions.addAll(((FunctionChain<?, ?>)func).chain);
        } else {
            functions.add(func);
        }
        return (Chainer<IN, OUT2>) this;
    }

    @SuppressWarnings("unchecked")
    public Function<IN, OUT> build() {
        // If empty, it's a noop function. If one element, there's no need for a chain.
        return new FunctionChain<IN, OUT>(functions);
    }
}

public static final <X, Y, Z> Function<X, Z> combine(
        final Function<X, Y> primary,
        final Function<Y, Z> secondary
) {
    return chain(primary).then(secondary).build();
}