All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dakusui.valid8j_pcond.experimentals.currying.multi.MultiFunction Maven / Gradle / Ivy

The newest version!
package com.github.dakusui.valid8j_pcond.experimentals.currying.multi;

import com.github.dakusui.valid8j_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.valid8j_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.valid8j_pcond.forms.Functions#curry(MultiFunction)} method.
 *
 * @param  The type of the returned value.
 */
public interface MultiFunction extends Function, 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 returnType();

  class Impl extends PrintableFunction, R> implements MultiFunction {
    private final String         name;
    private final List> parameterTypes;

    protected Impl(
        Object creator,
        List args,
        Supplier formatter,
        String name,
        Function, ? extends R> function,
        List> 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  The type of value returned by the multi-function built by this object.
   */
  class Builder {
    private final Object                                              creator        = Builder.class;
    private       List                                        identityArgs;
    private       String                                              name           = "(anonymous)";
    private final Function, ? extends R> body;
    private final List>                                      parameterTypes = new LinkedList<>();
    private       Supplier                                    formatter      = () -> name + "(" + parameterTypes.stream().map(Class::getSimpleName).collect(joining(",")) + ")";

    public Builder(Function, R> body) {
      requireNonNull(body);
      this.body = args -> body.apply(requireArgumentListSize(requireNonNull(args), parameterTypes.size()));
    }

    public Builder addParameters(List> parameterTypes) {
      requireNonNull(parameterTypes).stream().map(this::addParameter).forEach(Objects::requireNonNull);
      return this;
    }

    public Builder identityArgs(List identity) {
      this.identityArgs = requireNonNull(identity);
      return this;
    }

    public Builder name(String name) {
      this.name = name;
      return this;
    }

    public Builder addParameter(Class parameterType) {
      this.parameterTypes.add(requireNonNull(parameterType));
      return this;
    }

    public Builder formatter(Supplier formatter) {
      this.formatter = requireNonNull(formatter);
      return this;
    }

    public MultiFunction $() {
      return new Impl(
          this.creator,
          this.identityArgs,
          this.formatter,
          this.name,
          this.body,
          this.parameterTypes
      );
    }
  }
}