如何使用Java 8编写函数的泛型迭代?

0xb*_*00d 8 java generics functor java-8

请考虑以下两个功能:

public static <X, Y, U, V extends X> Function<U, Y> composite(
    Function<X, Y> first, Function<U, V> second)
{
    Objects.requireNonNull(first);
    Objects.requireNonNull(second);
    return (U arg) -> first.apply(second.apply(arg));
}

public static <X, Y extends X> Function<X, ?> iterate(Function<X, Y> function, int n)
{
    if (n < 0)
        return null;
    if (n == 0)
        return (X arg) -> arg;  
    Objects.requireNonNull(function);

    Function<X, Y> iteration = function;
    for (; n > 1; --n)
        iteration = composite(function, iteration);
    return iteration;
}
Run Code Online (Sandbox Code Playgroud)

composite(first, second)计算组合物firstsecond,iterate(function, n)计算nth 迭代function.

虽然限制Y extends X足以满足任何要求n > 0,但我们遇到了一些问题n == 0.在数学上,iterate应该产生身份功能.但是,我们也需要X extends Y,也就是说X == Y.

请考虑以下示例

Function<Double, Double> nthSquareRoot = iterate(Math::sqrt, n);
Run Code Online (Sandbox Code Playgroud)

这会产生错误消息:

Type mismatch: cannot convert from Function<Double,capture#2-of ?> to Function<Double,Double>
Run Code Online (Sandbox Code Playgroud)

这里最好的选择是什么?如果n == 1,我们可以检查是否X可以接受Y.我想听听其他选项和一些想法如何执行此检查(据我所知,没有简单的解决方案来检查两个通用参数是否相等).

Bri*_*etz 8

尝试:

public static<X> UnaryOperator<X> iterate(UnaryOperator<X> f, int n) { ... }
Run Code Online (Sandbox Code Playgroud)

如果Y <:X,那么从X到Y的函数也是从X到X的函数,你应该能够做你想要的.


ass*_*ias 5

您需要更改结果的类型以考虑通配符:

Function<Double, ? extends Double> nthSquareRoot = iterate(Math::sqrt, 2);
Run Code Online (Sandbox Code Playgroud)

以及iterate方法的签名:

public static <X, Y extends X> Function<X, ? extends X> iterate(Function<X, Y> function, int n)
Run Code Online (Sandbox Code Playgroud)

例:

public static <X, Y extends X> Function<X, ? extends X> iterate(Function<X, Y> function, int n) {
  if (n < 0) return null;
  if (n == 0) return Function.identity();

  Function<X, Y> iteration = Objects.requireNonNull(function);
  for (; n > 1; --n) {
    iteration = composite(function, iteration);
  }
  return iteration;
}

public static void main(String[] args) {
  Function<Double, ? extends Double> nthSquareRoot = iterate(Math::sqrt, 2);
  System.out.println(nthSquareRoot.apply(81d));
}
Run Code Online (Sandbox Code Playgroud)

按预期打印9.


或者你可以使用UnaryOperator:

public static <X> UnaryOperator<X> iterate(UnaryOperator<X> function, int n) {
  if (n < 0) return null;
  if (n == 0) return UnaryOperator.identity();

  UnaryOperator<X> iteration = Objects.requireNonNull(function);
  for (int i = 0; i < n - 1; i++) {
    iteration = composite(function::apply, iteration::apply)::apply;
  }
  return iteration;
}

public static void main(String[] args) {
  UnaryOperator<Double> nthSquareRoot = iterate(Math::sqrt, 2);
  System.out.println(nthSquareRoot.apply(81d));
}
Run Code Online (Sandbox Code Playgroud)