package toolsBugs;
import java.util.Optional; 
import java.util.function.BiFunction; 
import java.util.function.Function; 

public final class OptionalMapN { 

	public static <T, U, R> Optional<R> map2(BiFunction<T, U, R> f, Optional<T> tOpt, Optional<U> uOpt) { 
		return tOpt.flatMap(t -> uOpt.map(u -> f.apply(t, u))); 
	} 

	public static <T, U, V, R> Optional<R> map3_doesNotCompileWithJavac9( 
			TriFunction<T, U, V, R> f, 
			Optional<T> tOpt, 
			Optional<U> uOpt, 
			Optional<V> vOpt) { 

		return map2(Function::apply, map2(f::apply, tOpt, uOpt), vOpt); 
	} 

	public static <T, U, V, R> Optional<R> map3_alsoDoesNotCompileWithJavac9( 
			TriFunction<T, U, V, R> f, 
			Optional<T> tOpt, 
			Optional<U> uOpt, 
			Optional<V> vOpt) { 

		return map2((vrFunc, v) -> vrFunc.apply(v), map2((t, u) -> f.apply(t, u), tOpt, uOpt), vOpt); 
	} 

	public static <T, U, V, R> Optional<R> map3_compilesWithBothJavac8_144andJavac9( 
			TriFunction<T, U, V, R> f, 
			Optional<T> tOpt, 
			Optional<U> uOpt, 
			Optional<V> vOpt) { 

		Optional<R> rOpt1 = map2((Function<V,R> vrFunction, V v) -> vrFunction.apply(v), map2(f::apply, tOpt, uOpt), vOpt); 
		Optional<R> rOpt2 = map2(Function::apply, map2((T t, U u) -> f.apply(t, u), tOpt, uOpt), vOpt); 
		Optional<R> rOpt3 = map2(Function::apply, map2(f::partialApply, tOpt, uOpt), vOpt); 
		return rOpt3; 
	} 

	private OptionalMapN() { 
	} 

	@FunctionalInterface 
	public static interface TriFunction<T, U, V, R> { 

		public R apply(T t, U u, V v); 

		public default Function<V, R> apply(T t, U u) { 
			return v -> apply(t, u, v); 
		} 

		public default Function<V,R> partialApply(T t, U u) { 
			return v -> apply(t, u, v); 
		} 

	} 

} 