import java.util.function.BiFunction; import java.util.function.Function; interface DuallyParametric { R match(Function aFn, Function bFn); static DuallyParametric a(Aa a) { return null; } DuallyParametric b(Bb b); Bl foldLeft(BiFunction fn, Bl b, Iterable as); default DuallyParametric merge(DuallyParametric first, BiFunction aFn, BiFunction bFn, Iterable> others) { return foldLeft((x, y) -> x.match(a1 -> y.match(a2 -> a(aFn.apply(a1, a2)), b -> a(a1)), b1 -> y.match(DuallyParametric::a, b2 -> b(bFn.apply(b1, b2)))), first, others); } } interface DuallyParametric1 { default R match(Function aFn) { return null; } static DuallyParametric1 a() { return null; } void foldLeft(Function fn, Bl b); default void merge() { foldLeft((x) -> x.match(a1 -> match(a2 -> a())), this); } }