/*-
 * #%L
 * Functional interfaces for SciJava-based libraries.
 * %%
 * Copyright (C) 2021 - 2024 SciJava developers.
 * %%
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * #L%
 */
/*
 * This is autogenerated source code -- DO NOT EDIT. Instead, edit the
 * corresponding template in templates/ and rerun bin/generate.groovy.
 */

package org.scijava.function;

import java.util.HashMap;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;


/**
 * Container class for
 * higher-<a href="https://en.wikipedia.org/wiki/Arity">arity</a>
 * {@link Function}-style functional interfaces&mdash;i.e. with functional
 * method {@code apply} with a number of arguments corresponding to the arity.
 * <ul>
 * <li>For 0-arity (nullary) functions, use {@link Producer} (and notice the
 * functional method there is named {@link Producer#create()}).</li>
 * <li>For 1-arity (unary) functions, use {@link Function}.</li>
 * <li>For 2-arity (binary) functions, use {@link BiFunction}.</li>
 * </ul>
 *
 * @author Curtis Rueden
 * @author Gabriel Selzer
 */
public final class Functions {

	private Functions() {
		// NB: Prevent instantiation of utility class.
	}

	/**
	 * All known function types and their arities. The entries are sorted by
	 * arity, i.e., the {@code i}-th entry has an arity of {@code i}. It might be
	 * nice to use a BiMap from e.g. Google Guava, but that would require a
	 * dependency on that component :(
	 */
	public static final HashMap<Integer, Class<?>> ALL_FUNCTIONS;
	public static final HashMap<Class<?>, Integer> ALL_ARITIES;

	static {
		ALL_FUNCTIONS = new HashMap<>(10);
		ALL_ARITIES = new HashMap<>(10);
		ALL_FUNCTIONS.put(0, Producer.class);
		ALL_ARITIES.put(Producer.class, 0);
		ALL_FUNCTIONS.put(1, Function.class);
		ALL_ARITIES.put(Function.class, 1);
		ALL_FUNCTIONS.put(2, BiFunction.class);
		ALL_ARITIES.put(BiFunction.class, 2);
		ALL_FUNCTIONS.put(3, Functions.Arity3.class);
		ALL_ARITIES.put(Functions.Arity3.class, 3);
		ALL_FUNCTIONS.put(4, Functions.Arity4.class);
		ALL_ARITIES.put(Functions.Arity4.class, 4);
		ALL_FUNCTIONS.put(5, Functions.Arity5.class);
		ALL_ARITIES.put(Functions.Arity5.class, 5);
		ALL_FUNCTIONS.put(6, Functions.Arity6.class);
		ALL_ARITIES.put(Functions.Arity6.class, 6);
		ALL_FUNCTIONS.put(7, Functions.Arity7.class);
		ALL_ARITIES.put(Functions.Arity7.class, 7);
		ALL_FUNCTIONS.put(8, Functions.Arity8.class);
		ALL_ARITIES.put(Functions.Arity8.class, 8);
		ALL_FUNCTIONS.put(9, Functions.Arity9.class);
		ALL_ARITIES.put(Functions.Arity9.class, 9);
		ALL_FUNCTIONS.put(10, Functions.Arity10.class);
		ALL_ARITIES.put(Functions.Arity10.class, 10);
		ALL_FUNCTIONS.put(11, Functions.Arity11.class);
		ALL_ARITIES.put(Functions.Arity11.class, 11);
		ALL_FUNCTIONS.put(12, Functions.Arity12.class);
		ALL_ARITIES.put(Functions.Arity12.class, 12);
		ALL_FUNCTIONS.put(13, Functions.Arity13.class);
		ALL_ARITIES.put(Functions.Arity13.class, 13);
		ALL_FUNCTIONS.put(14, Functions.Arity14.class);
		ALL_ARITIES.put(Functions.Arity14.class, 14);
		ALL_FUNCTIONS.put(15, Functions.Arity15.class);
		ALL_ARITIES.put(Functions.Arity15.class, 15);
		ALL_FUNCTIONS.put(16, Functions.Arity16.class);
		ALL_ARITIES.put(Functions.Arity16.class, 16);
	}

	/**
	 * @return {@code true} if the given type is a known
	 *         function type, {@code false} otherwise.<br>
	 *         Note that only the type itself and not its type hierarchy is
	 *         considered.
	 * @throws NullPointerException If {@code c} is {@code null}.
	 */
	public static boolean isFunction(Class<?> c) {
		try {
			var superType = superType(c);
			return true;
		} catch (IllegalArgumentException e) {
			return false;
		}
	}

	public static Class<?> superType(Class<?> c) {
		if (ALL_FUNCTIONS.containsValue(c)) return c;
		for(var func : ALL_ARITIES.keySet()) {
			if (func.isAssignableFrom(c)) return func;
		}
		throw new IllegalArgumentException(c + " is not a subclass of any known Functions!");
	}

	/**
	 * @param arity an {@code int} corresponding to a {@code Function} of that
	 *          arity.
	 * @return the {@code Function} of arity {@code arity}.
	 * @throws IllegalArgumentException iff there is no known {@link Function} of
	 *           arity {@code arity}.
	 */
	public static Class<?> functionOfArity(int arity) {
		if (ALL_FUNCTIONS.containsKey(arity)) return ALL_FUNCTIONS.get(arity);
		throw new IllegalArgumentException("No Function of arity " + arity);
	}

	/**
	 * @param c the {@link Class} of unknown arity
	 * @return the arity of {@code c}, or {@code -1} if {@code c} is <b>not</b> a
	 *         {@code Function}.
	 */
	public static int arityOf(Class<?> c) {
		return ALL_ARITIES.getOrDefault(c, -1);
	}

	/**
	 * A 3-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity3<I1, I2, I3, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity3<I1, I2, I3, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3) -> after.apply(apply(in1, in2, in3));
		}
	}

	/**
	 * A 4-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity4<I1, I2, I3, I4, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity4<I1, I2, I3, I4, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4) -> after.apply(apply(in1, in2, in3, in4));
		}
	}

	/**
	 * A 5-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity5<I1, I2, I3, I4, I5, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity5<I1, I2, I3, I4, I5, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5) -> after.apply(apply(in1, in2, in3, in4, in5));
		}
	}

	/**
	 * A 6-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity6<I1, I2, I3, I4, I5, I6, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity6<I1, I2, I3, I4, I5, I6, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6) -> after.apply(apply(in1, in2, in3, in4, in5, in6));
		}
	}

	/**
	 * A 7-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity7<I1, I2, I3, I4, I5, I6, I7, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity7<I1, I2, I3, I4, I5, I6, I7, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7));
		}
	}

	/**
	 * A 8-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <I8> the type of argument 8 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity8<I1, I2, I3, I4, I5, I6, I7, I8, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @param in8 function argument 8
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity8<I1, I2, I3, I4, I5, I6, I7, I8, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7, in8));
		}
	}

	/**
	 * A 9-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <I8> the type of argument 8 to the function
	 * @param <I9> the type of argument 9 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity9<I1, I2, I3, I4, I5, I6, I7, I8, I9, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @param in8 function argument 8
		 * @param in9 function argument 9
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity9<I1, I2, I3, I4, I5, I6, I7, I8, I9, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7, in8, in9));
		}
	}

	/**
	 * A 10-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <I8> the type of argument 8 to the function
	 * @param <I9> the type of argument 9 to the function
	 * @param <I10> the type of argument 10 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity10<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @param in8 function argument 8
		 * @param in9 function argument 9
		 * @param in10 function argument 10
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity10<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7, in8, in9, in10));
		}
	}

	/**
	 * A 11-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <I8> the type of argument 8 to the function
	 * @param <I9> the type of argument 9 to the function
	 * @param <I10> the type of argument 10 to the function
	 * @param <I11> the type of argument 11 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity11<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @param in8 function argument 8
		 * @param in9 function argument 9
		 * @param in10 function argument 10
		 * @param in11 function argument 11
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity11<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11));
		}
	}

	/**
	 * A 12-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <I8> the type of argument 8 to the function
	 * @param <I9> the type of argument 9 to the function
	 * @param <I10> the type of argument 10 to the function
	 * @param <I11> the type of argument 11 to the function
	 * @param <I12> the type of argument 12 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity12<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @param in8 function argument 8
		 * @param in9 function argument 9
		 * @param in10 function argument 10
		 * @param in11 function argument 11
		 * @param in12 function argument 12
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity12<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12));
		}
	}

	/**
	 * A 13-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <I8> the type of argument 8 to the function
	 * @param <I9> the type of argument 9 to the function
	 * @param <I10> the type of argument 10 to the function
	 * @param <I11> the type of argument 11 to the function
	 * @param <I12> the type of argument 12 to the function
	 * @param <I13> the type of argument 13 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity13<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @param in8 function argument 8
		 * @param in9 function argument 9
		 * @param in10 function argument 10
		 * @param in11 function argument 11
		 * @param in12 function argument 12
		 * @param in13 function argument 13
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12, I13 in13);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity13<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12, I13 in13) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13));
		}
	}

	/**
	 * A 14-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <I8> the type of argument 8 to the function
	 * @param <I9> the type of argument 9 to the function
	 * @param <I10> the type of argument 10 to the function
	 * @param <I11> the type of argument 11 to the function
	 * @param <I12> the type of argument 12 to the function
	 * @param <I13> the type of argument 13 to the function
	 * @param <I14> the type of argument 14 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity14<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @param in8 function argument 8
		 * @param in9 function argument 9
		 * @param in10 function argument 10
		 * @param in11 function argument 11
		 * @param in12 function argument 12
		 * @param in13 function argument 13
		 * @param in14 function argument 14
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12, I13 in13, I14 in14);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity14<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12, I13 in13, I14 in14) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14));
		}
	}

	/**
	 * A 15-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <I8> the type of argument 8 to the function
	 * @param <I9> the type of argument 9 to the function
	 * @param <I10> the type of argument 10 to the function
	 * @param <I11> the type of argument 11 to the function
	 * @param <I12> the type of argument 12 to the function
	 * @param <I13> the type of argument 13 to the function
	 * @param <I14> the type of argument 14 to the function
	 * @param <I15> the type of argument 15 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity15<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @param in8 function argument 8
		 * @param in9 function argument 9
		 * @param in10 function argument 10
		 * @param in11 function argument 11
		 * @param in12 function argument 12
		 * @param in13 function argument 13
		 * @param in14 function argument 14
		 * @param in15 function argument 15
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12, I13 in13, I14 in14, I15 in15);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity15<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12, I13 in13, I14 in14, I15 in15) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14, in15));
		}
	}

	/**
	 * A 16-arity specialization of {@link Function}.
	 *
	 * @param <I1> the type of argument 1 to the function
	 * @param <I2> the type of argument 2 to the function
	 * @param <I3> the type of argument 3 to the function
	 * @param <I4> the type of argument 4 to the function
	 * @param <I5> the type of argument 5 to the function
	 * @param <I6> the type of argument 6 to the function
	 * @param <I7> the type of argument 7 to the function
	 * @param <I8> the type of argument 8 to the function
	 * @param <I9> the type of argument 9 to the function
	 * @param <I10> the type of argument 10 to the function
	 * @param <I11> the type of argument 11 to the function
	 * @param <I12> the type of argument 12 to the function
	 * @param <I13> the type of argument 13 to the function
	 * @param <I14> the type of argument 14 to the function
	 * @param <I15> the type of argument 15 to the function
	 * @param <I16> the type of argument 16 to the function
	 * @param <O> the type of the output of the function
	 * @see Function
	 */
	@FunctionalInterface
	public interface Arity16<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, O> {

		/**
		 * Applies this function to the given arguments.
		 *
		 * @param in1 function argument 1
		 * @param in2 function argument 2
		 * @param in3 function argument 3
		 * @param in4 function argument 4
		 * @param in5 function argument 5
		 * @param in6 function argument 6
		 * @param in7 function argument 7
		 * @param in8 function argument 8
		 * @param in9 function argument 9
		 * @param in10 function argument 10
		 * @param in11 function argument 11
		 * @param in12 function argument 12
		 * @param in13 function argument 13
		 * @param in14 function argument 14
		 * @param in15 function argument 15
		 * @param in16 function argument 16
		 * @return the function output
		 */
		O apply(I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12, I13 in13, I14 in14, I15 in15, I16 in16);

		/**
		 * Returns a composed function that first applies this function to its
		 * input, and then applies the {@code after} function to the result. If
		 * evaluation of either function throws an exception, it is relayed to the
		 * caller of the composed function.
		 *
		 * @param <O2> the type of output of the {@code after} function, and of the
		 *          composed function
		 * @param after the function to apply after this function is applied
		 * @return a composed function that first applies this function and then
		 *         applies the {@code after} function
		 * @throws NullPointerException if after is null
		 */
		default <O2> Arity16<I1, I2, I3, I4, I5, I6, I7, I8, I9, I10, I11, I12, I13, I14, I15, I16, O2> andThen(Function<? super O, ? extends O2> after)
		{
			Objects.requireNonNull(after);
			return (I1 in1, I2 in2, I3 in3, I4 in4, I5 in5, I6 in6, I7 in7, I8 in8, I9 in9, I10 in10, I11 in11, I12 in12, I13 in13, I14 in14, I15 in15, I16 in16) -> after.apply(apply(in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, in12, in13, in14, in15, in16));
		}
	}

	public interface ArityN<O> {

		O apply(Object... ins);

		Object op();
	}

	/**
	 * Converts a {@link org.scijava.function.Producer} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link org.scijava.function.Producer}
	 * @param f the {@link org.scijava.function.Producer} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link org.scijava.function.Producer}
	 */
	public static <O> Functions.ArityN<O> nary(Producer<O> f) {

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return f.create();
			}

			@Override
			public Producer<O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link java.util.function.Function} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link java.util.function.Function}
	 * @param f the {@link java.util.function.Function} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link java.util.function.Function}
	 */
	public static <O> Functions.ArityN<O> nary(Function<?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Function<Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0]);
			}

			@Override
			public Function<?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link java.util.function.BiFunction} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link java.util.function.BiFunction}
	 * @param f the {@link java.util.function.BiFunction} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link java.util.function.BiFunction}
	 */
	public static <O> Functions.ArityN<O> nary(BiFunction<?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (BiFunction<Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1]);
			}

			@Override
			public BiFunction<?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity3} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity3}
	 * @param f the {@link Arity3} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity3}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity3<?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity3<Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2]);
			}

			@Override
			public Functions.Arity3<?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity4} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity4}
	 * @param f the {@link Arity4} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity4}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity4<?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity4<Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3]);
			}

			@Override
			public Functions.Arity4<?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity5} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity5}
	 * @param f the {@link Arity5} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity5}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity5<?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity5<Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4]);
			}

			@Override
			public Functions.Arity5<?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity6} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity6}
	 * @param f the {@link Arity6} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity6}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity6<?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity6<Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
			}

			@Override
			public Functions.Arity6<?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity7} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity7}
	 * @param f the {@link Arity7} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity7}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity7<?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity7<Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6]);
			}

			@Override
			public Functions.Arity7<?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity8} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity8}
	 * @param f the {@link Arity8} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity8}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity8<?, ?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity8<Object, Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6], ins[7]);
			}

			@Override
			public Functions.Arity8<?, ?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity9} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity9}
	 * @param f the {@link Arity9} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity9}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity9<?, ?, ?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity9<Object, Object, Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6], ins[7], ins[8]);
			}

			@Override
			public Functions.Arity9<?, ?, ?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity10} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity10}
	 * @param f the {@link Arity10} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity10}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity10<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity10<Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6], ins[7], ins[8], ins[9]);
			}

			@Override
			public Functions.Arity10<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity11} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity11}
	 * @param f the {@link Arity11} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity11}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity11<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity11<Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6], ins[7], ins[8], ins[9], ins[10]);
			}

			@Override
			public Functions.Arity11<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity12} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity12}
	 * @param f the {@link Arity12} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity12}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity12<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity12<Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6], ins[7], ins[8], ins[9], ins[10], ins[11]);
			}

			@Override
			public Functions.Arity12<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity13} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity13}
	 * @param f the {@link Arity13} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity13}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity13<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity13<Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6], ins[7], ins[8], ins[9], ins[10], ins[11], ins[12]);
			}

			@Override
			public Functions.Arity13<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity14} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity14}
	 * @param f the {@link Arity14} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity14}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity14<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity14<Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6], ins[7], ins[8], ins[9], ins[10], ins[11], ins[12], ins[13]);
			}

			@Override
			public Functions.Arity14<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity15} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity15}
	 * @param f the {@link Arity15} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity15}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity15<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity15<Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6], ins[7], ins[8], ins[9], ins[10], ins[11], ins[12], ins[13], ins[14]);
			}

			@Override
			public Functions.Arity15<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

	/**
	 * Converts a {@link Arity16} to a {@link ArityN}.
	 * 
	 * @param <O> the type variable linked the output of the {@link Arity16}
	 * @param f the {@link Arity16} to be converted into a {@link ArityN}
	 * @return a {@link ArityN} created from the {@link Arity16}
	 */
	public static <O> Functions.ArityN<O> nary(Functions.Arity16<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> f) {

		// NB f must be cast to accept a set of input Objects for apply
		@SuppressWarnings("unchecked")
		var func = (Functions.Arity16<Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, O>) f;

		return new ArityN<>() {

			@Override
			public O apply(Object... ins) {
				return func.apply(ins[0], ins[1], ins[2], ins[3], ins[4], ins[5], ins[6], ins[7], ins[8], ins[9], ins[10], ins[11], ins[12], ins[13], ins[14], ins[15]);
			}

			@Override
			public Functions.Arity16<?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, O> op() {
				return f;
			}
		};
	}

}
