package ch.claude_martin;
import java.util.function.*;
/**
* My Y Combinator can handle any reference type (primitives will be auto-boxed,
* that's why I can use <code>long/Long</code> here). However, since I'm using
* {@link UnaryOperator}, the recursive function must return the same type as
* it's (second) argument. Factorial is a good example of this. Instead of long,
* it could take a {@link java.math.BigInteger} and also return one.
*
*/
public class YComb {
/**
* This is the <i>recursive</i> type of the function that will apply itself to
* itself. This is how the recursion work.s A function needs itself as the first
* parameter, so it then can call itself recursively.
* <p>See this partial application in the code below:<br/>
* <code>b -> b.apply(b)</code>
*/
interface Fn2Op<T> extends Function<Fn2Op<T>, UnaryOperator<T>> {
}
/** Prints the factorial of <code>args[0]</code>.*/
public static void main(String args[]) {
final UnaryOperator<UnaryOperator<Long>> factorial =
f -> n -> (n == 0) ? 1L : n * f.apply(n - 1);
System.out.println(apply(factorial, Long.parseLong(args[0])));
}
/**
* Takes any <i>recursive</i> function (which takes itself and an argument) and
* argument and returns the result. The argument and the return value are of the
* same type <code>T</code>.
*
* @param <T> The type of <code>arg</code> and return value
* @param fn The recursive function (in curried form)
* @param arg The argument for the function
* @return the result of applying <code>arg</code> to <code>fn</code>
*/
private static <T> T apply(UnaryOperator<UnaryOperator<T>> fn, T arg) {
return ((Function<UnaryOperator<UnaryOperator<T>>, UnaryOperator<T>>)
a -> ((Fn2Op<T>) b -> b.apply(b))
.apply(
c -> a.apply(
x -> c.apply(c).apply(x)
)
)).apply(fn).apply(arg);
}
}
Comments
0 B
|👍
/👎