MultiFunction.java
package com.github.dakusui.pcond.experimentals.currying.multi;
import com.github.dakusui.pcond.core.printable.PrintableFunction;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import static com.github.dakusui.pcond.internals.InternalChecks.requireArgumentListSize;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
/**
* An interface that represents a function that can have more than one parameters.
* This interface is often used in combination with {@link com.github.dakusui.pcond.forms.Functions#curry(MultiFunction)} method.
*
* @param <R> The type of the returned value.
*/
public interface MultiFunction<R> extends Function<List<? super Object>, R> {
/**
* Returns a name of this function.
*
* @return The name of this function.
*/
String name();
/**
* Returns the number of parameters that this function can take.
*
* @return the number of parameters
*/
int arity();
/**
* The expected type of the {@code i}th parameter.
*
* @param i The parameter index.
* @return The type of {@code i}th parameter.
*/
Class<?> parameterType(int i);
/**
* The type of the value returned by this function.
*
* @return The type of the returned value.
*/
Class<? extends R> returnType();
class Impl<R> extends PrintableFunction<List<? super Object>, R> implements MultiFunction<R> {
private final String name;
private final List<Class<?>> parameterTypes;
protected Impl(
Object creator,
List<Object> args,
Supplier<String> formatter,
String name,
Function<? super List<? super Object>, ? extends R> function,
List<Class<?>> parameterTypes) {
super(
creator,
args,
formatter,
function);
this.name = name;
this.parameterTypes = new ArrayList<>(parameterTypes);
}
@Override
public String name() {
return name;
}
@Override
public int arity() {
return parameterTypes.size();
}
@Override
public Class<?> parameterType(int i) {
return parameterTypes.get(i);
}
}
/**
* A builder for a {@link MultiFunction} instance.
*
* @param <R> The type of value returned by the multi-function built by this object.
*/
class Builder<R> {
private final Object creator = Builder.class;
private List<Object> identityArgs;
private String name = "(anonymous)";
private final Function<? super List<? super Object>, ? extends R> body;
private final List<Class<?>> parameterTypes = new LinkedList<>();
private Supplier<String> formatter = () -> name + "(" + parameterTypes.stream().map(Class::getSimpleName).collect(joining(",")) + ")";
public Builder(Function<List<Object>, R> body) {
requireNonNull(body);
this.body = args -> body.apply(requireArgumentListSize(requireNonNull(args), parameterTypes.size()));
}
public Builder<R> addParameters(List<Class<?>> parameterTypes) {
requireNonNull(parameterTypes).stream().map(this::addParameter).forEach(Objects::requireNonNull);
return this;
}
public Builder<R> identityArgs(List<Object> identity) {
this.identityArgs = requireNonNull(identity);
return this;
}
public Builder<R> name(String name) {
this.name = name;
return this;
}
public Builder<R> addParameter(Class<?> parameterType) {
this.parameterTypes.add(requireNonNull(parameterType));
return this;
}
public Builder<R> formatter(Supplier<String> formatter) {
this.formatter = requireNonNull(formatter);
return this;
}
public MultiFunction<R> $() {
return new Impl<R>(
this.creator,
this.identityArgs,
this.formatter,
this.name,
this.body,
this.parameterTypes
);
}
}
}