RosettaCodeData/Task/Ackermann-function/Java/ackermann-function-4.java

146 lines
3.9 KiB
Java

import java.math.BigInteger;
import java.util.Stack;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public interface Ackermann {
public static Ackermann new_(BigInteger number1, BigInteger number2, Stack<BigInteger> stack, boolean flag) {
return $.new_(number1, number2, stack, flag);
}
public static void main(String... arguments) {
$.main(arguments);
}
public BigInteger number1();
public BigInteger number2();
public Stack<BigInteger> stack();
public boolean flag();
public enum $ {
$$;
private static final BigInteger ZERO = BigInteger.ZERO;
private static final BigInteger ONE = BigInteger.ONE;
private static final BigInteger TWO = BigInteger.valueOf(2);
private static final BigInteger THREE = BigInteger.valueOf(3);
private static final BigInteger FOUR = BigInteger.valueOf(4);
private static Ackermann new_(BigInteger number1, BigInteger number2, Stack<BigInteger> stack, boolean flag) {
return (FunctionalAckermann) field -> {
switch (field) {
case number1: return number1;
case number2: return number2;
case stack: return stack;
case flag: return flag;
default: throw new UnsupportedOperationException(
field instanceof Field
? "Field checker has not been updated properly."
: "Field is not of the correct type."
);
}
};
}
private static final BinaryOperator<BigInteger> ACKERMANN =
TailRecursive.new_(
(BigInteger number1, BigInteger number2) ->
new_(
number1,
number2,
Stream.of(number1).collect(
Collectors.toCollection(Stack::new)
),
false
)
,
ackermann -> {
BigInteger number1 = ackermann.number1();
BigInteger number2 = ackermann.number2();
Stack<BigInteger> stack = ackermann.stack();
if (!stack.empty() && !ackermann.flag()) {
number1 = stack.pop();
}
switch (number1.intValue()) {
case 0:
return new_(
number1,
number2.add(ONE),
stack,
false
);
case 1:
return new_(
number1,
number2.add(TWO),
stack,
false
);
case 2:
return new_(
number1,
number2.multiply(TWO).add(THREE),
stack,
false
);
default:
if (ZERO.equals(number2)) {
return new_(
number1.subtract(ONE),
ONE,
stack,
true
);
} else {
stack.push(number1.subtract(ONE));
return new_(
number1,
number2.subtract(ONE),
stack,
true
);
}
}
},
ackermann -> ackermann.stack().empty(),
Ackermann::number2
)::apply
;
private static void main(String... arguments) {
System.out.println(ACKERMANN.apply(FOUR, TWO));
}
private enum Field {
number1,
number2,
stack,
flag
}
@FunctionalInterface
private interface FunctionalAckermann extends FunctionalField<Field>, Ackermann {
@Override
public default BigInteger number1() {
return field(Field.number1);
}
@Override
public default BigInteger number2() {
return field(Field.number2);
}
@Override
public default Stack<BigInteger> stack() {
return field(Field.stack);
}
@Override
public default boolean flag() {
return field(Field.flag);
}
}
}
}