DulcetAirman icon

Y Combinator in Java

DulcetAirman | PRO | 10/14/17 08:19:27 AM UTC | 0 ⭐ | 1241 👁️ | Never ⏰ | []
Java |

1.87 KB

|

None

|

0 👍

/

0 👎

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

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎