75 lines
2.7 KiB
Java
75 lines
2.7 KiB
Java
import java.math.BigDecimal;
|
|
import java.math.BigInteger;
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.function.Function;
|
|
import java.util.function.UnaryOperator;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.LongStream;
|
|
|
|
@FunctionalInterface
|
|
public interface Y<FUNCTION> extends SelfApplicable<FixedPoint<FUNCTION>> {
|
|
public static void main(String... arguments) {
|
|
BigInteger TWO = BigInteger.ONE.add(BigInteger.ONE);
|
|
|
|
Function<Number, Long> toLong = Number::longValue;
|
|
Function<Number, BigInteger> toBigInteger = toLong.andThen(BigInteger::valueOf);
|
|
|
|
/* Based on https://gist.github.com/aruld/3965968/#comment-604392 */
|
|
Y<VarargsFunction<Number, Number>> combinator = y -> f -> x -> f.apply(y.selfApply().apply(f)).apply(x);
|
|
FixedPoint<VarargsFunction<Number, Number>> fixedPoint = combinator.selfApply();
|
|
|
|
VarargsFunction<Number, Number> fibonacci = fixedPoint.apply(
|
|
f -> VarargsFunction.upgrade(
|
|
toBigInteger.andThen(
|
|
n -> (n.compareTo(TWO) <= 0)
|
|
? 1
|
|
: new BigInteger(f.apply(n.subtract(BigInteger.ONE)).toString())
|
|
.add(new BigInteger(f.apply(n.subtract(TWO)).toString()))
|
|
)
|
|
)
|
|
);
|
|
|
|
VarargsFunction<Number, Number> factorial = fixedPoint.apply(
|
|
f -> VarargsFunction.upgrade(
|
|
toBigInteger.andThen(
|
|
n -> (n.compareTo(BigInteger.ONE) <= 0)
|
|
? 1
|
|
: n.multiply(new BigInteger(f.apply(n.subtract(BigInteger.ONE)).toString()))
|
|
)
|
|
)
|
|
);
|
|
|
|
VarargsFunction<Number, Number> ackermann = fixedPoint.apply(
|
|
f -> VarargsFunction.upgrade(
|
|
(BigInteger m, BigInteger n) -> m.equals(BigInteger.ZERO)
|
|
? n.add(BigInteger.ONE)
|
|
: f.apply(
|
|
m.subtract(BigInteger.ONE),
|
|
n.equals(BigInteger.ZERO)
|
|
? BigInteger.ONE
|
|
: f.apply(m, n.subtract(BigInteger.ONE))
|
|
)
|
|
).transformArguments(toBigInteger)
|
|
);
|
|
|
|
Map<String, VarargsFunction<Number, Number>> functions = new HashMap<>();
|
|
functions.put("fibonacci", fibonacci);
|
|
functions.put("factorial", factorial);
|
|
functions.put("ackermann", ackermann);
|
|
|
|
Map<VarargsFunction<Number, Number>, Number[]> parameters = new HashMap<>();
|
|
parameters.put(functions.get("fibonacci"), new Number[]{20});
|
|
parameters.put(functions.get("factorial"), new Number[]{10});
|
|
parameters.put(functions.get("ackermann"), new Number[]{3, 2});
|
|
|
|
functions.entrySet().stream().parallel().map(
|
|
entry -> entry.getKey()
|
|
+ Arrays.toString(parameters.get(entry.getValue()))
|
|
+ " = "
|
|
+ entry.getValue().apply(parameters.get(entry.getValue()))
|
|
).forEach(System.out::println);
|
|
}
|
|
}
|