// Path: src/main/java/co/unruly/control/ThrowingLambdas.java
// public interface ThrowingLambdas {
// 
//     /**
//      * A Function which may throw a checked exception
//      */
//     @FunctionalInterface
//     interface ThrowingFunction<I, O, X extends Exception> {
//         O apply(I input) throws X;
// 
//         default <T> ThrowingFunction<I, T, X> andThen(Function<O, T> nextFunction) {
//             return x -> nextFunction.apply(apply(x));
//         }
// 
//         default <T> ThrowingFunction<T, O, X> compose(Function<T, I> nextFunction) {
//             return x -> apply(nextFunction.apply(x));
//         }
// 
//         /**
//          * Converts the provided function into a regular Function, where any thrown exceptions are
//          * wrapped in a RuntimeException.
//          */
//         static <I, O, X extends Exception> Function<I, O> throwingRuntime(ThrowingFunction<I, O, X> f) {
//             return x -> {
//                 try {
//                     return f.apply(x);
//                 } catch (Exception ex) {
//                     throw new RuntimeException(ex);
//                 }
//             };
//         }
//     }
// 
//     /**
//      * A Consumer which may throw a checked exception
//      */
//     @FunctionalInterface
//     interface ThrowingConsumer<T, X extends Exception> {
//         void accept(T item) throws X;
// 
//         /**
//          * Converts the provided consumer into a regular Consumer, where any thrown exceptions are
//          * wrapped in a RuntimeException.
//          */
//         static <T, X extends Exception> Consumer<T> throwingRuntime(ThrowingConsumer<T, X> p) {
//             return x -> {
//                 try {
//                     p.accept(x);
//                 } catch (Exception ex) {
//                     throw new RuntimeException(ex);
//                 }
//             };
//         }
//     }
// 
//     /**
//      * A BiFunction which may throw a checked exception
//      */
//     @FunctionalInterface
//     interface ThrowingBiFunction<A, B, R, X extends Exception> {
//         R apply(A first, B second) throws X;
// 
//         /**
//          * Converts the provided bifunction into a regular BiFunction, where any thrown exceptions
//          * are wrapped in a RuntimeException
//          */
//         static <A, B, R, X extends Exception> BiFunction<A, B, R> throwingRuntime(ThrowingBiFunction<A, B, R, X> f) {
//             return (a, b) -> {
//                 try {
//                     return f.apply(a, b);
//                 } catch (Exception ex) {
//                     throw new RuntimeException(ex);
//                 }
//             };
//         }
//     }
// 
//     /**
//      * A Predicate which may throw a checked exception
//      */
//     @FunctionalInterface
//     interface ThrowingPredicate<T, X extends Exception> {
//         boolean test(T item) throws X;
// 
//         /**
//          * Converts the provided predicate into a regular Predicate, where any thrown exceptions
//          * are wrapped in a RuntimeException
//          */
//         static <T, X extends Exception> Predicate<T> throwingRuntime(ThrowingPredicate<T, X> p) {
//             return x -> {
//                 try {
//                     return p.test(x);
//                 } catch (Exception ex) {
//                     throw new RuntimeException(ex);
//                 }
//             };
//         }
//     }
// 
//     static <T, X extends Exception> Predicate<T> throwsWhen(ThrowingConsumer<T, X> consumer) {
//         return t -> {
//             try {
//                 consumer.accept(t);
//                 return false;
//             } catch (Exception ex) {
//                 return true;
//             }
//         };
//     }
// 
//     static <T, X extends Exception> Predicate<T> doesntThrow(ThrowingConsumer<T, X> consumer) {
//         return t -> {
//             try {
//                 consumer.accept(t);
//                 return true;
//             } catch (Exception ex) {
//                 return false;
//             }
//         };
//     }
// }
// 
// Path: src/main/java/co/unruly/control/result/Result.java
// public static <S, F> Result<S, F> failure(F error) {
//     return new Failure<>(error);
// }
// 
// Path: src/main/java/co/unruly/control/result/Result.java
// public static <S, F> Result<S, F> success(S value) {
//     return new Success<>(value);
// }
// 
// Path: src/main/java/co/unruly/control/result/Transformers.java
// static <S, F> Function<Result<Stream<S>, F>, Stream<Result<S, F>>> unwrapSuccesses() {
//     return r -> r.either(
//         successes -> successes.map(Result::success),
//         failure -> Stream.of(Result.failure(failure))
//     );
// }


import co.unruly.control.ThrowingLambdas;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import static co.unruly.control.result.Result.failure;
import static co.unruly.control.result.Result.success;
import static co.unruly.control.result.Transformers.unwrapSuccesses;
import static java.util.function.Function.identity;
     * Returns a function which takes a value, applies the provided function to it, and returns
     * a success of the output of that function. If an exception is thrown, return a failure of
     * the specified failure case value.
     *
     * Whilst we take a ThrowingFunction which throws a specific checked exception type X, our
     * eventual Result is of the more general type Exception. That's because it's also possible for the
     * function to throw other types of RuntimeException, and we have two choices: don't catch (or rethrow)
     * RuntimeException, or have a more general failure type. Rethrowing exceptions goes against the whole
     * point of constraining the error path, so we opt for the latter.
     *
     * If the provided function throws an Error, we don't catch that. Errors in general are not
     * intended to be caught.
     *
     * Note that idiomatic handling of Exceptions as failure type does allow specialised catch blocks
     * on specific exception types.
     */
    static <IS, OS, X extends Exception, F> Function<IS, Result<OS, F>> tryTo(
        ThrowingLambdas.ThrowingFunction<IS, OS, X> throwingFunction,
        F failureCase
    ) {
        return tryTo(throwingFunction, __ -> failureCase);
    }


    /**
     * Returns a function which takes a value, applies the provided stream-returning function to it,
     * and return a stream which is the stream returned by the function, with each element wrapped in
     * a success, or a single failure of the exception thrown by that function if it threw an exception.
     */
    static <IS, OS, X extends Exception> Function<IS, Stream<Result<OS, Exception>>> tryAndUnwrap(ThrowingLambdas.ThrowingFunction<IS, Stream<OS>, X> f) {
// Path: src/main/java/co/unruly/control/ThrowingLambdas.java
// public interface ThrowingLambdas {
// 
//     /**
//      * A Function which may throw a checked exception
//      */
//     @FunctionalInterface
//     interface ThrowingFunction<I, O, X extends Exception> {
//         O apply(I input) throws X;
// 
//         default <T> ThrowingFunction<I, T, X> andThen(Function<O, T> nextFunction) {
//             return x -> nextFunction.apply(apply(x));
//         }
// 
//         default <T> ThrowingFunction<T, O, X> compose(Function<T, I> nextFunction) {
//             return x -> apply(nextFunction.apply(x));
//         }
// 
//         /**
//          * Converts the provided function into a regular Function, where any thrown exceptions are
//          * wrapped in a RuntimeException.
//          */
//         static <I, O, X extends Exception> Function<I, O> throwingRuntime(ThrowingFunction<I, O, X> f) {
//             return x -> {
//                 try {
//                     return f.apply(x);
//                 } catch (Exception ex) {
//                     throw new RuntimeException(ex);
//                 }
//             };
//         }
//     }
// 
//     /**
//      * A Consumer which may throw a checked exception
//      */
//     @FunctionalInterface
//     interface ThrowingConsumer<T, X extends Exception> {
//         void accept(T item) throws X;
// 
//         /**
//          * Converts the provided consumer into a regular Consumer, where any thrown exceptions are
//          * wrapped in a RuntimeException.
//          */
//         static <T, X extends Exception> Consumer<T> throwingRuntime(ThrowingConsumer<T, X> p) {
//             return x -> {
//                 try {
//                     p.accept(x);
//                 } catch (Exception ex) {
//                     throw new RuntimeException(ex);
//                 }
//             };
//         }
//     }
// 
//     /**
//      * A BiFunction which may throw a checked exception
//      */
//     @FunctionalInterface
//     interface ThrowingBiFunction<A, B, R, X extends Exception> {
//         R apply(A first, B second) throws X;
// 
//         /**
//          * Converts the provided bifunction into a regular BiFunction, where any thrown exceptions
//          * are wrapped in a RuntimeException
//          */
//         static <A, B, R, X extends Exception> BiFunction<A, B, R> throwingRuntime(ThrowingBiFunction<A, B, R, X> f) {
//             return (a, b) -> {
//                 try {
//                     return f.apply(a, b);
//                 } catch (Exception ex) {
//                     throw new RuntimeException(ex);
//                 }
//             };
//         }
//     }
// 
//     /**
//      * A Predicate which may throw a checked exception
//      */
//     @FunctionalInterface
//     interface ThrowingPredicate<T, X extends Exception> {
//         boolean test(T item) throws X;
// 
//         /**
//          * Converts the provided predicate into a regular Predicate, where any thrown exceptions
//          * are wrapped in a RuntimeException
//          */
//         static <T, X extends Exception> Predicate<T> throwingRuntime(ThrowingPredicate<T, X> p) {
//             return x -> {
//                 try {
//                     return p.test(x);
//                 } catch (Exception ex) {
//                     throw new RuntimeException(ex);
//                 }
//             };
//         }
//     }
// 
//     static <T, X extends Exception> Predicate<T> throwsWhen(ThrowingConsumer<T, X> consumer) {
//         return t -> {
//             try {
//                 consumer.accept(t);
//                 return false;
//             } catch (Exception ex) {
//                 return true;
//             }
//         };
//     }
// 
//     static <T, X extends Exception> Predicate<T> doesntThrow(ThrowingConsumer<T, X> consumer) {
//         return t -> {
//             try {
//                 consumer.accept(t);
//                 return true;
//             } catch (Exception ex) {
//                 return false;
//             }
//         };
//     }
// }
// 
// Path: src/main/java/co/unruly/control/result/Result.java
// public static <S, F> Result<S, F> failure(F error) {
//     return new Failure<>(error);
// }
// 
// Path: src/main/java/co/unruly/control/result/Result.java
// public static <S, F> Result<S, F> success(S value) {
//     return new Success<>(value);
// }
// 
// Path: src/main/java/co/unruly/control/result/Transformers.java
// static <S, F> Function<Result<Stream<S>, F>, Stream<Result<S, F>>> unwrapSuccesses() {
//     return r -> r.either(
//         successes -> successes.map(Result::success),
//         failure -> Stream.of(Result.failure(failure))
//     );
// }


// Path: src/main/java/co/unruly/control/result/Introducers.java
import co.unruly.control.ThrowingLambdas;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
import static co.unruly.control.result.Result.failure;
import static co.unruly.control.result.Result.success;
import static co.unruly.control.result.Transformers.unwrapSuccesses;
import static java.util.function.Function.identity;

     * Returns a function which takes a value, applies the provided function to it, and returns
     * a success of the output of that function. If an exception is thrown, return a failure of
     * the specified failure case value.
     *
     * Whilst we take a ThrowingFunction which throws a specific checked exception type X, our
     * eventual Result is of the more general type Exception. That's because it's also possible for the
     * function to throw other types of RuntimeException, and we have two choices: don't catch (or rethrow)
     * RuntimeException, or have a more general failure type. Rethrowing exceptions goes against the whole
     * point of constraining the error path, so we opt for the latter.
     *
     * If the provided function throws an Error, we don't catch that. Errors in general are not
     * intended to be caught.
     *
     * Note that idiomatic handling of Exceptions as failure type does allow specialised catch blocks
     * on specific exception types.
     */
    static <IS, OS, X extends Exception, F> Function<IS, Result<OS, F>> tryTo(
        ThrowingLambdas.ThrowingFunction<IS, OS, X> throwingFunction,
        F failureCase
    ) {
        return tryTo(throwingFunction, __ -> failureCase);
    }


    /**
     * Returns a function which takes a value, applies the provided stream-returning function to it,
     * and return a stream which is the stream returned by the function, with each element wrapped in
     * a success, or a single failure of the exception thrown by that function if it threw an exception.
     */
    static <IS, OS, X extends Exception> Function<IS, Stream<Result<OS, Exception>>> tryAndUnwrap(ThrowingLambdas.ThrowingFunction<IS, Stream<OS>, X> f) {
        return tryTo(f).andThen(unwrapSuccesses());