import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @FunctionalInterface interface FunctionalField> { public Object untypedField(FIELD field); @SuppressWarnings("unchecked") public default VALUE field(FIELD field) { return (VALUE) untypedField(field); } public static > Object throwOnUndefinedField(FIELD field) throws Error { throw new InternalError(field + " is undefined"); } } @FunctionalInterface interface Cell { public VALUE select(BiFunction, ? extends VALUE> cons, Supplier nil); public static VALUE nil(BiFunction, ? extends VALUE> cons, Supplier nil) { return nil.get(); } public default int size() { return select( (element, next) -> 1 + next.size(), () -> 0 ); } public default Cell first(int size) { return Optional.of(size) .>map(s -> select( (element, next) -> s == 0 ? nil() : cons(element, next.first(s - 1)) , Cell::nil )) .orElseThrow(IllegalArgumentException::new) ; } public default Cell map(Function mapper) { return select( (element, next) -> Cell.cons(mapper.apply(element), next.map(mapper)), Cell::nil ); } public default Cell flatMap(Function> mapper) { return select( (element, next) -> mapper .apply(element) .select( Cell::cons, () -> next.flatMap(mapper) ) , Cell::nil ); } public interface Cons { public ELEMENT element(); public Cell next(); public default VALUE cons(BiFunction, ? extends VALUE> cons, Supplier nil) { return cons.apply(element(), next()); } public static Cons new_(ELEMENT element, Cell next) { return $.$Cons.new_(element, next); } public enum $ { ; @FunctionalInterface private interface $Cons extends Cons, FunctionalField<$Cons.Field> { public enum Field { element, next } @Override public default ELEMENT element() { return field(Field.element); } public default Cell next() { return field(Field.next); } public static $Cons new_(ELEMENT element, Cell next) { return field -> { switch (field) { case element: return element; case next: return next; default: return FunctionalField.throwOnUndefinedField(field); } }; } } } } public static Cell nil() { return Cell::nil; } public static Cell cons(ELEMENT element, Cell next) { Objects.requireNonNull(element); Objects.requireNonNull(next); return Cons.new_(element, next)::cons; } public static void main(String... arguments) { System.out.println(nil() == nil()); // true Cell cell = cons(1, cons(2, cons(3, nil()))) ; System.out.println(cell.size() == 3); // true System.out.println(cell.first(2).size() == 2); // true } } public interface Main { public static void main(String... arguments) { Cell.main(arguments); } }