Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a generic iteration of a function using Java 8?

Please consider the following two functions:

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

While composite(first, second) computes the composition of first and second, iterate(function, n) computes the nth iterate of function.

While the restriction Y extends X suffices for any n > 0, we've got some problem with n == 0. Mathematically, iterate should yield the identity function. However, therefore we would need X extends Y, i.e. X == Y, as well.

Please consider the following example

Function<Double, Double> nthSquareRoot = iterate(Math::sqrt, n);

This yields the error message:

Type mismatch: cannot convert from Function<Double,capture#2-of ?> to Function<Double,Double>

What's the best option here? If n == 1, we could check if X is acceptable as Y. I would like to hear other options and some ideas how this check can be performed (as far as I know, there is no simple solution to check two generic parameters for equality).

like image 765
0xbadf00d Avatar asked May 24 '14 21:05

0xbadf00d


People also ask

What is the new method introduced in Java 8 to iterate through a collection?

Introduced in Java 8, the forEach loop provides programmers with a new, concise and interesting way to iterate over a collection.

How an iterate object can be used to iterate a list in Java?

By using this iterator object, you can access each element in the collection, one element at a time. Obtain an iterator to the start of the collection by calling the collection's iterator() method. Set up a loop that makes a call to hasNext(). Have the loop iterate as long as hasNext() returns true.


1 Answers

Try:

public static<X> UnaryOperator<X> iterate(UnaryOperator<X> f, int n) { ... }

If Y <: X, then a function from X to Y is also a function from X to X, and you should be able to do what you want.

like image 179
Brian Goetz Avatar answered Nov 16 '22 03:11

Brian Goetz