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.BiFunction;
import java.util.function.Function;
/*
ResultExpression uses .success(v) to lift v into context, .map and .flatMap to apply computation, of a Result type. The flatmap is
called bind in some languages. Feel free to reuse in another Result or either type with the similar monadic properties.
*/
/**
* Lifts a Result into the context of expression, in which usage of a Result type is easily used,
* without making nested structures.
*/
public class ResultExpression {
public static <T1, E> ResultExpression.Step1<T1, E> of(Result<T1, E> r) {
return new ResultExpression.Step1<>(r);
}
public static <T1, E> ResultExpression.Step1<T1, E> ofValue(T1 v) {
return new 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> ResultExpression.Step2<T1, T2, E> bind(Function<T1, Result<T2, E>> f) {
return new ResultExpression.Step2<>(r, f);
}
public <T2> ResultExpression.Step2<T1, T2, E> map(Function<T1, T2> f) {
return new 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> ResultExpression.Step3<T1, T2, T3, E> bind(BiFunction<T1, T2, Result<T3, E>> f2) {
return new ResultExpression.Step3<>(r, f, f2);
}
public <T3> ResultExpression.Step3<T1, T2, T3, E> map(BiFunction<T1, T2, T3> f2) {
return new 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> ResultExpression.Step4<T1, T2, T3, T4, E> bind(ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3) {
return new ResultExpression.Step4<>(r, f1, f2, f3);
}
public <T4> ResultExpression.Step4<T1, T2, T3, T4, E> map(ResultExpression.Function3<T1, T2, T3, T4> f3) {
return new ResultExpression.Step4<>(r, f1, f2, (t1, t2, t3) -> Result.success(f3.apply(t1, t2, t3)));
}
public <R> Result<R, E> yield(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 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,
ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3) {
this.r = r;
this.f1 = f1;
this.f2 = f2;
this.f3 = f3;
}
public <T5> ResultExpression.Step5<T1, T2, T3, T4, T5, E> bind(ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4) {
return new ResultExpression.Step5<>(r, f1, f2, f3, f4);
}
public <T5> ResultExpression.Step5<T1, T2, T3, T4, T5, E> map(ResultExpression.Function4<T1, T2, T3, T4, T5> f4) {
return new ResultExpression.Step5<>(r, f1, f2, f3, (t1, t2, t3, t4) -> Result.success(f4.apply(t1, t2, t3, t4)));
}
public <R> Result<R, E> yield(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 ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
private final 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,
ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
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> ResultExpression.Step5.Step6<T1, T2, T3, T4, T5, T6, E> bind(ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5) {
return new ResultExpression.Step5.Step6<>(r, f1, f2, f3, f4, f5);
}
public <T6> ResultExpression.Step5.Step6<T1, T2, T3, T4, T5, T6, E> map(ResultExpression.Function5<T1, T2, T3, T4, T5, T6> f5) {
return new 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(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 ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
private final ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4;
private final 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,
ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4,
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> ResultExpression.Step5.Step7<T1, T2, T3, T4, T5, T6, T7, E> bind(ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6) {
return new ResultExpression.Step5.Step7<>(r, f1, f2, f3, f4, f5, f6);
}
public <T7> ResultExpression.Step5.Step7<T1, T2, T3, T4, T5, T6, T7, E> map(ResultExpression.Function6<T1, T2, T3, T4, T5, T6, T7> f6) {
return new 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(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 ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
private final ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4;
private final ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5;
private final 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,
ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4,
ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5,
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> ResultExpression.Step5.Step8<T1, T2, T3, T4, T5, T6, T7, T8, E> bind(ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, Result<T8, E>> f7) {
return new ResultExpression.Step5.Step8<>(r, f1, f2, f3, f4, f5, f6, f7);
}
public <T8> ResultExpression.Step5.Step8<T1, T2, T3, T4, T5, T6, T7, T8, E> map(ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, T8> f7) {
return new 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(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 ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
private final ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4;
private final ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5;
private final ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6;
private final 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,
ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4,
ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5,
ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6,
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> ResultExpression.Step5.Step8.Step9<T1, T2, T3, T4, T5, T6, T7, T8, T9, E> bind(ResultExpression.Function8<T1, T2, T3, T4, T5, T6, T7, T8, Result<T9, E>> f8) {
return new ResultExpression.Step5.Step8.Step9<>(r, f1, f2, f3, f4, f5, f6, f7, f8);
}
public <T9> ResultExpression.Step5.Step8.Step9<T1, T2, T3, T4, T5, T6, T7, T8, T9, E> map(ResultExpression.Function8<T1, T2, T3, T4, T5, T6, T7, T8, T9> f8) {
return new 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(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 ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3;
private final ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4;
private final ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5;
private final ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6;
private final ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, Result<T8, E>> f7;
private final 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,
ResultExpression.Function3<T1, T2, T3, Result<T4, E>> f3,
ResultExpression.Function4<T1, T2, T3, T4, Result<T5, E>> f4,
ResultExpression.Function5<T1, T2, T3, T4, T5, Result<T6, E>> f5,
ResultExpression.Function6<T1, T2, T3, T4, T5, T6, Result<T7, E>> f6,
ResultExpression.Function7<T1, T2, T3, T4, T5, T6, T7, Result<T8, E>> f7,
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(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);
}
}