Result.java

package lucidglitch;
//        MIT License
//
//        Copyright (c) 2025 Stefan von Stein
//        Permission is hereby granted, free of charge, to any person obtaining a copy
//        of this software and associated documentation files (the "Software"), to deal
//        in the Software without restriction, including without limitation the rights
//        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//        copies of the Software, and to permit persons to whom the Software is
//        furnished to do so, subject to the following conditions:
//
//        The above copyright notice and this permission notice shall be included in all
//        copies or substantial portions of the Software.
//
//        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//        SOFTWARE.


import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.BiFunction;

public sealed interface Result<T, E> permits Result.Success, Result.Failure {
    /**
     * Result in Success context
     */
    record Success<T, E>(T value) implements Result<T, E> {
    }

    /**
     * Result in Failure context
     */
    record Failure<T, E>(E error) implements Result<T, E> {
        @Override
        public boolean isSuccess() {
            return false;
        }
    }

    default  T value () {
        throw new IllegalStateException ( "Failure: " + error());
    };
    default E error () {
        throw new IllegalStateException ( "Success: " + value());
    };
    default boolean isSuccess(){
        return true;
    }
    @FunctionalInterface
    interface ThrowingSupplier<T, E extends Exception> {
        T get() throws E;
    }

    /**
     * Result in Success context
     */
    static <T, E> Result<T, E> success(T value) {
        return new Success<>(value);
    }
    /**
     * Result in Failure context
     */
    static <T, E> Result<T, E> failure(E error) {
        return new Failure<>(error);
    }

    /**
     * Result in Success context, or Failure id Exception is thrown by supplier
     */
    static <T, E extends Exception> Result<T, E> trial(ThrowingSupplier<T, E> supplier) {
        try {
            return success(supplier.get());
        } catch (Exception e) {
            //noinspection unchecked
            return failure((E) e); // Cast to E since we expect it to extend Exception
        }
    }

    /**
     * Run an expression withing a try block, and return any exception in a Failure
     */
    static <T, E extends Exception, F> Result<T, F> trial(ThrowingSupplier<T, E> supplier,
                                                          Function<? super Exception, F> exceptionMapper) {

                try {
                    return success(supplier.get());
                }catch (Exception e) {
                    return failure(exceptionMapper.apply(e));
                }
            }



    /**
     * Apply mapper to Success but not to Failure
     */
    default <U> Result<U, E> map(Function<? super T, ? extends U> mapper) {
        return switch (this) {
            case Success( var value) -> success(mapper.apply(value));
            case Failure( var error) -> failure(error);
        };
    }

    default Result<T,E> whenOk(Consumer<T> consumer) {
        if(isSuccess())
            consumer.accept(value());
        return this;
    }
    default Result<T,E> whenError(Consumer<E> consumer) {
        if(!isSuccess())
            consumer.accept(error());
        return this;
    }
    /**
     * Apply mapper to Success but not to Failure, and emmit Failure i mapper throws a runtime exception
     */
    default <U> Result<U, E> mapTrial(Function<? super T, ? extends U> mapper) {
        return switch (this) {
            case Success(var value) -> {
                try {
                    yield success(mapper.apply(value));
                }catch (Exception e) {
                    yield failure((E) e);
                }
            }
            case Failure(var error) -> failure( error);
        };
    }

    /**
     * Apply mapper to Success but not to Failure, and emmit Failure i mapper throws, but transform any
     * exception with exceptionMapper
     */
    default <U> Result<U, E> mapTrial(Function<? super T, ? extends U> mapper,
                                      Function<? super Exception, E> exceptionMapper) {
        return switch (this) {
            case Success(var value) -> {
                try {
                    yield success(mapper.apply(value));
                }catch (Exception e) {
                    yield failure(exceptionMapper.apply(e));
                }
            }
            case Failure(var error) -> failure( error);
        };
    }

    /**
     * Apply mapper to Failure, rather than Success, which is just propagated.
     */
    default <F> Result<T, F> mapFailure(Function<? super E, ? extends F> mapper) {
        return switch (this) {
            case Success(var value) -> success(value);
            case Failure(var failure) -> failure(mapper.apply(failure));
        };
    }

    /**
     * Apply mapper to Success value, but let mapper decide if it is Success or Failure
     */
    default <U> Result<U, E> flatMap(Function<? super T, Result<U, E>> mapper) {
        return switch (this) {
            case Success(var value) -> mapper.apply(value);
            case Failure(var error) -> failure(error);
        };
    }

    @SuppressWarnings("unchecked")
    default  <U> Result<U, E> join() {
        return switch (this){
            case Success(Result<?,?> inner) -> (Result<U,E>) inner;
            case Success(var e) -> throw new IllegalStateException("Value is not a Result");
            case Failure (var e) -> failure(e);
        };
    }

    public static class ResultExpression {

        public static <T1, E> foo.ResultExpression.Step1<T1, E> of(Result<T1, E> r) {
            return new foo.ResultExpression.Step1<>(r);
        }

        public static <T1, E> foo.ResultExpression.Step1<T1, E> ofValue(T1 v) {
            return new foo.ResultExpression.Step1<>(Result.success(v));
        }


        public static class Step1<T1, E> {
            private final Result<T1, E> r;

            public Step1(Result<T1, E> r) {
                this.r = r;
            }

            public <T2> foo.ResultExpression.Step2<T1, T2, E> bind(Function<T1, Result<T2, E>> f) {
                return new foo.ResultExpression.Step2<>(r, f);
            }

            public <T2> foo.ResultExpression.Step2<T1, T2, E> map(Function<T1, T2> f) {

                return new foo.ResultExpression.Step2<>(r, t1 -> Result.success(f.apply(t1)));
            }

            public <R> Result<R, E> yield(Function<T1, R> f) {
                return r.map(t1 -> f.apply(t1));
            }
        }


        public static class Step2<T1, T2, E> {
            private final Result<T1, E> r;
            private final Function<T1, Result<T2, E>> f;

            public Step2(Result<T1, E> r, Function<T1, Result<T2, E>> f) {
                this.r = r;
                this.f = f;
            }

            public <T3> foo.ResultExpression.Step3<T1, T2, T3, E> bind(BiFunction<T1, T2, Result<T3, E>> f2) {
                return new foo.ResultExpression.Step3<>(r, f, f2);
            }

            public <T3> foo.ResultExpression.Step3<T1, T2, T3, E> map(BiFunction<T1, T2, T3> f2) {
                return new foo.ResultExpression.Step3<>(r, f, (t1, t2) -> Result.success(f2.apply(t1, t2)));
            }

            public <R> Result<R, E> yield(BiFunction<T1, T2, R> yieldFn) {
                return r.flatMap(t1 ->
                        f.apply(t1).map(t2 -> yieldFn.apply(t1, t2))
                );
            }
        }

        public static class Step3<T1, T2, T3, E> {
            private final Result<T1, E> r;
            private final Function<T1, Result<T2, E>> f1;
            private final BiFunction<T1, T2, Result<T3, E>> f2;

            public Step3(Result<T1, E> r,
                         Function<T1, Result<T2, E>> f1,
                         BiFunction<T1, T2, Result<T3, E>> f2) {
                this.r = r;
                this.f1 = f1;
                this.f2 = f2;
            }

            public <T4> foo.ResultExpression.Step4<T1, T2, T3, T4, E> bind(foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3) {
                return new foo.ResultExpression.Step4<>(r, f1, f2, f3);
            }

            public <T4> foo.ResultExpression.Step4<T1, T2, T3, T4, E> map(foo.ResultExpression.Function3<T1, T2, T3, T4> f3) {
                return new foo.ResultExpression.Step4<>(r, f1, f2, (t1, t2, t3) -> Result.success(f3.apply(t1, t2, t3)));
            }

            public <R> Result<R, E> yield(foo.ResultExpression.Function3<T1, T2, T3, R> yieldFn) {
                return r.flatMap(t1 ->
                        f1.apply(t1).flatMap(t2 ->
                                f2.apply(t1, t2).map(t3 ->
                                        yieldFn.apply(t1, t2, t3)
                                )
                        )
                );
            }
        }

        public static class Step4<T1, T2, T3, T4, E> {
            private final Result<T1, E> r;
            private final Function<T1, Result<T2, E>> f1;
            private final BiFunction<T1, T2, Result<T3, E>> f2;
            private final foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;

            public Step4(Result<T1, E> r,
                         Function<T1, Result<T2, E>> f1,
                         BiFunction<T1, T2, Result<T3, E>> f2,
                         foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3) {
                this.r = r;
                this.f1 = f1;
                this.f2 = f2;
                this.f3 = f3;
            }

            public <T5> foo.ResultExpression.Step5<T1, T2, T3, T4, T5, E> bind(foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4) {
                return new foo.ResultExpression.Step5<>(r, f1, f2, f3, f4);
            }

            public <T5> foo.ResultExpression.Step5<T1, T2, T3, T4, T5, E> map(foo.ResultExpression.Function4<T1, T2, T3, T4, T5> f4) {
                return new foo.ResultExpression.Step5<>(r, f1, f2, f3, (t1, t2, t3, t4) -> Result.success(f4.apply(t1, t2, t3, t4)));
            }

            public <R> Result<R, E> yield(foo.ResultExpression.Function4<T1, T2, T3, T4, R> yieldFn) {
                return r.flatMap(t1 ->
                        f1.apply(t1).flatMap(t2 ->
                                f2.apply(t1, t2).flatMap(t3 ->
                                        f3.apply(t1, t2, t3).map(t4 ->
                                                yieldFn.apply(t1, t2, t3, t4)
                                        )
                                )
                        )
                );
            }
        }

        public static class Step5<T1, T2, T3, T4, T5, E> {
            private final Result<T1, E> r;
            private final Function<T1, Result<T2, E>> f1;
            private final BiFunction<T1, T2, Result<T3, E>> f2;
            private final foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
            private final foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4;

            public Step5(Result<T1, E> r,
                         Function<T1, Result<T2, E>> f1,
                         BiFunction<T1, T2, Result<T3, E>> f2,
                         foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
                         foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4) {
                this.r = r;
                this.f1 = f1;
                this.f2 = f2;
                this.f3 = f3;
                this.f4 = f4;
            }

            public <T6> foo.ResultExpression.Step5.Step6<T1, T2, T3, T4, T5, T6, E> bind(foo.ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5) {
                return new foo.ResultExpression.Step5.Step6<>(r, f1, f2, f3, f4, f5);
            }

            public <T6> foo.ResultExpression.Step5.Step6<T1, T2, T3, T4, T5, T6, E> map(foo.ResultExpression.Function5<T1, T2, T3, T4, T5, T6> f5) {
                return new foo.ResultExpression.Step5.Step6<>(r, f1, f2, f3, f4, (t1, t2, t3, t4, t5) -> Result.success(f5.apply(t1, t2, t3, t4, t5)));
            }


            public <R> Result<R, E> yield(foo.ResultExpression.Function5<T1, T2, T3, T4, T5, R> yieldFn) {
                return r.flatMap(t1 ->
                        f1.apply(t1).flatMap(t2 ->
                                f2.apply(t1, t2).flatMap(t3 ->
                                        f3.apply(t1, t2, t3).flatMap(t4 ->
                                                f4.apply(t1, t2, t3, t4).map(t5 ->
                                                        yieldFn.apply(t1, t2, t3, t4, t5)
                                                )
                                        )
                                )
                        )
                );
            }

            public static class Step6<T1, T2, T3, T4, T5, T6, E> {
                private final Result<T1, E> r;
                private final Function<T1, Result<T2, E>> f1;
                private final BiFunction<T1, T2, Result<T3, E>> f2;
                private final foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
                private final foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4;
                private final foo.ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5;

                public Step6(Result<T1, E> r,
                             Function<T1, Result<T2, E>> f1,
                             BiFunction<T1, T2, Result<T3, E>> f2,
                             foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
                             foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4,
                             foo.ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5) {

                    this.r = r;
                    this.f1 = f1;
                    this.f2 = f2;
                    this.f3 = f3;
                    this.f4 = f4;
                    this.f5 = f5;
                }

                public <T7> foo.ResultExpression.Step5.Step7<T1, T2, T3, T4, T5, T6, T7, E> bind(foo.ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6) {
                    return new foo.ResultExpression.Step5.Step7<>(r, f1, f2, f3, f4, f5, f6);
                }

                public <T7> foo.ResultExpression.Step5.Step7<T1, T2, T3, T4, T5, T6, T7, E> map(foo.ResultExpression.Function6<T1, T2, T3, T4, T5, T6, T7> f6) {
                    return new foo.ResultExpression.Step5.Step7<>(r, f1, f2, f3, f4, f5, (t1, t2, t3, t4, t5, t6) -> Result.success(f6.apply(t1, t2, t3, t4, t5, t6)));
                }

                public <R> Result<R, E> yield(foo.ResultExpression.Function6<T1, T2, T3, T4, T5, T6, R> yieldFn) {
                    return r.flatMap(t1 ->
                            f1.apply(t1).flatMap(t2 ->
                                    f2.apply(t1, t2).flatMap(t3 ->
                                            f3.apply(t1, t2, t3).flatMap(t4 ->
                                                    f4.apply(t1, t2, t3, t4).flatMap(t5 ->
                                                            f5.apply(t1, t2, t3, t4, t5).map(t6 ->
                                                                    yieldFn.apply(t1, t2, t3, t4, t5, t6)
                                                            )
                                                    )
                                            )
                                    )
                            )
                    );
                }
            }

            public static class Step7<T1, T2, T3, T4, T5, T6, T7, E> {
                private final Result<T1, E> r;
                private final Function<T1, Result<T2, E>> f1;
                private final BiFunction<T1, T2, Result<T3, E>> f2;
                private final foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
                private final foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4;
                private final foo.ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5;
                private final foo.ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6;

                public Step7(Result<T1, E> r,
                             Function<T1, Result<T2, E>> f1,
                             BiFunction<T1, T2, Result<T3, E>> f2,
                             foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
                             foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4,
                             foo.ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5,
                             foo.ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6) {

                    this.r = r;
                    this.f1 = f1;
                    this.f2 = f2;
                    this.f3 = f3;
                    this.f4 = f4;
                    this.f5 = f5;
                    this.f6 = f6;
                }

                public <T8> foo.ResultExpression.Step5.Step8<T1, T2, T3, T4, T5, T6, T7, T8, E> bind(foo.ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, Result<T8, E>> f7) {
                    return new foo.ResultExpression.Step5.Step8<>(r, f1, f2, f3, f4, f5, f6, f7);
                }

                public <T8> foo.ResultExpression.Step5.Step8<T1, T2, T3, T4, T5, T6, T7, T8, E> map(foo.ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, T8> f7) {
                    return new foo.ResultExpression.Step5.Step8<>(r, f1, f2, f3, f4, f5, f6, (t1, t2, t3, t4, t5, t6, t7) -> Result.success(f7.apply(t1, t2, t3, t4, t5, t6, t7)));
                }

                public <R> Result<R, E> yield(foo.ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, R> yieldFn) {
                    return r.flatMap(t1 ->
                            f1.apply(t1).flatMap(t2 ->
                                    f2.apply(t1, t2).flatMap(t3 ->
                                            f3.apply(t1, t2, t3).flatMap(t4 ->
                                                    f4.apply(t1, t2, t3, t4).flatMap(t5 ->
                                                            f5.apply(t1, t2, t3, t4, t5).flatMap(t6 ->
                                                                    f6.apply(t1, t2, t3, t4, t5, t6).map(t7 ->
                                                                            yieldFn.apply(t1, t2, t3, t4, t5, t6, t7)
                                                                    )
                                                            )
                                                    )
                                            )
                                    )
                            )
                    );
                }


            }

            public static class Step8<T1, T2, T3, T4, T5, T6, T7, T8, E> {
                private final Result<T1, E> r;
                private final Function<T1, Result<T2, E>> f1;
                private final BiFunction<T1, T2, Result<T3, E>> f2;
                private final foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
                private final foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4;
                private final foo.ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5;
                private final foo.ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6;
                private final foo.ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, Result<T8, E>> f7;

                public Step8(Result<T1, E> r,
                             Function<T1, Result<T2, E>> f1,
                             BiFunction<T1, T2, Result<T3, E>> f2,
                             foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
                             foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4,
                             foo.ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5,
                             foo.ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6,
                             foo.ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, Result<T8, E>> f7) {

                    this.r = r;
                    this.f1 = f1;
                    this.f2 = f2;
                    this.f3 = f3;
                    this.f4 = f4;
                    this.f5 = f5;
                    this.f6 = f6;
                    this.f7 = f7;
                }

                public <T9> foo.ResultExpression.Step5.Step8.Step9<T1, T2, T3, T4, T5, T6, T7, T8, T9, E> bind(foo.ResultExpression.Function8<T1, T2, T3, T4, T5, T6, T7, T8, Result<T9, E>> f8) {
                    return new foo.ResultExpression.Step5.Step8.Step9<>(r, f1, f2, f3, f4, f5, f6, f7, f8);
                }

                public <T9> foo.ResultExpression.Step5.Step8.Step9<T1, T2, T3, T4, T5, T6, T7, T8, T9, E> map(foo.ResultExpression.Function8<T1, T2, T3, T4, T5, T6, T7, T8, T9> f8) {
                    return new foo.ResultExpression.Step5.Step8.Step9<>(r, f1, f2, f3, f4, f5, f6, f7, (t1, t2, t3, t4, t5, t6, t7, t8) -> Result.success(f8.apply(t1, t2, t3, t4, t5, t6, t7, t8)));
                }

                public <R> Result<R, E> yield(foo.ResultExpression.Function8<T1, T2, T3, T4, T5, T6, T7, T8, R> yieldFn) {
                    return r.flatMap(t1 ->
                            f1.apply(t1).flatMap(t2 ->
                                    f2.apply(t1, t2).flatMap(t3 ->
                                            f3.apply(t1, t2, t3).flatMap(t4 ->
                                                    f4.apply(t1, t2, t3, t4).flatMap(t5 ->
                                                            f5.apply(t1, t2, t3, t4, t5).flatMap(t6 ->
                                                                    f6.apply(t1, t2, t3, t4, t5, t6).flatMap(t7 ->
                                                                            f7.apply(t1, t2, t3, t4, t5, t6, t7).map(t8 ->
                                                                                    yieldFn.apply(t1, t2, t3, t4, t5, t6, t7, t8)
                                                                            )
                                                                    )
                                                            )
                                                    )
                                            )
                                    )
                            )
                    );
                }

                public static class Step9<T1, T2, T3, T4, T5, T6, T7, T8, T9, E> {
                    private final Result<T1, E> r;
                    private final Function<T1, Result<T2, E>> f1;
                    private final BiFunction<T1, T2, Result<T3, E>> f2;
                    private final foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
                    private final foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4;
                    private final foo.ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5;
                    private final foo.ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6;
                    private final foo.ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, Result<T8, E>> f7;
                    private final foo.ResultExpression.Function8<T1, T2, T3, T4, T5, T6, T7, T8, Result<T9, E>> f8;

                    public Step9(Result<T1, E> r,
                                 Function<T1, Result<T2, E>> f1,
                                 BiFunction<T1, T2, Result<T3, E>> f2,
                                 foo.ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
                                 foo.ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4,
                                 foo.ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5,
                                 foo.ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6,
                                 foo.ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, Result<T8, E>> f7,
                                 foo.ResultExpression.Function8<T1, T2, T3, T4, T5, T6, T7, T8, Result<T9, E>> f8) {

                        this.r = r;
                        this.f1 = f1;
                        this.f2 = f2;
                        this.f3 = f3;
                        this.f4 = f4;
                        this.f5 = f5;
                        this.f6 = f6;
                        this.f7 = f7;
                        this.f8 = f8;
                    }

                    public <R> Result<R, E> yield(foo.ResultExpression.Function9<T1, T2, T3, T4, T5, T6, T7, T8, T9, R> yieldFn) {
                        return r.flatMap(t1 ->
                                f1.apply(t1).flatMap(t2 ->
                                        f2.apply(t1, t2).flatMap(t3 ->
                                                f3.apply(t1, t2, t3).flatMap(t4 ->
                                                        f4.apply(t1, t2, t3, t4).flatMap(t5 ->
                                                                f5.apply(t1, t2, t3, t4, t5).flatMap(t6 ->
                                                                        f6.apply(t1, t2, t3, t4, t5, t6).flatMap(t7 ->
                                                                                f7.apply(t1, t2, t3, t4, t5, t6, t7).flatMap(t8 ->
                                                                                        f8.apply(t1, t2, t3, t4, t5, t6, t7, t8).map(t9 ->
                                                                                                yieldFn.apply(t1, t2, t3, t4, t5, t6, t7, t8, t9)
                                                                                        )
                                                                                )
                                                                        )
                                                                )
                                                        )
                                                )
                                        )
                                )
                        );
                    }
                }
            }
        }

        @FunctionalInterface
        public interface Function3<A1, A2, A3, R> {
            R apply(A1 a1, A2 a2, A3 a3);
        }


        @FunctionalInterface
        public interface Function4<A1, A2, A3, A4, R> {
            R apply(A1 a1, A2 a2, A3 a3, A4 a4);
        }


        @FunctionalInterface
        public interface Function5<A1, A2, A3, A4, A5, R> {
            R apply(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5);
        }


        @FunctionalInterface
        public interface Function6<A1, A2, A3, A4, A5, A6, R> {
            R apply(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6);
        }


        @FunctionalInterface
        public interface Function7<A1, A2, A3, A4, A5, A6, A7, R> {
            R apply(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7);
        }


        @FunctionalInterface
        public interface Function8<A1, A2, A3, A4, A5, A6, A7, A8, R> {
            R apply(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8);
        }


        @FunctionalInterface
        public interface Function9<A1, A2, A3, A4, A5, A6, A7, A8, A9, R> {
            R apply(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9);
        }
    }
    }