请考虑以下两个功能:
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;
}
虽然composite(first, second)
计算first
和second
的{{3}},但iterate(function, n)
计算nth
composition function
}}
虽然限制Y extends X
适用于任何n > 0
,但我们对n == 0
遇到了一些问题。在数学上,iterate
应该产生身份函数。但是,我们也需要X extends Y
,即X == Y
。
请考虑以下示例
Function<Double, Double> nthSquareRoot = iterate(Math::sqrt, n);
这会产生错误消息:
Type mismatch: cannot convert from Function<Double,capture#2-of ?> to Function<Double,Double>
这里最好的选择是什么?如果n == 1
,我们可以检查X
是否可以接受为Y
。我想听听其他选项和一些想法如何执行此检查(据我所知,没有简单的解决方案来检查两个通用参数是否相等)。
答案 0 :(得分:8)
尝试:
public static<X> UnaryOperator<X> iterate(UnaryOperator<X> f, int n) { ... }
如果Y&lt;:X,那么从X到Y的函数也是从X到X的函数,你应该能够做你想做的事。
答案 1 :(得分:5)
您需要更改结果的类型以考虑通配符:
Function<Double, ? extends Double> nthSquareRoot = iterate(Math::sqrt, 2);
以及iterate
方法的签名:
public static <X, Y extends X> Function<X, ? extends X> iterate(Function<X, Y> function, int n)
示例:
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));
}
按预期打印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));
}