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

org.opencastproject.util.data.functions.Functions Maven / Gradle / Ivy

There is a newer version: 16.7
Show newest version
/**
 * Licensed to The Apereo Foundation under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 *
 * The Apereo Foundation licenses this file to you under the Educational
 * Community License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License
 * at:
 *
 *   http://opensource.org/licenses/ecl2.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */


package org.opencastproject.util.data.functions;

import static org.opencastproject.util.data.Either.left;
import static org.opencastproject.util.data.Either.right;
import static org.opencastproject.util.data.Monadics.mlist;
import static org.opencastproject.util.data.Option.option;

import org.opencastproject.util.data.Effect;
import org.opencastproject.util.data.Effect0;
import org.opencastproject.util.data.Effect2;
import org.opencastproject.util.data.Either;
import org.opencastproject.util.data.Function;
import org.opencastproject.util.data.Function0;
import org.opencastproject.util.data.Function2;
import org.opencastproject.util.data.Option;
import org.opencastproject.util.data.Predicate;
import org.opencastproject.util.data.Tuple;

import com.entwinemedia.fn.Fn;

import java.util.List;
import java.util.Map;

/** General purpose functions, especially function transformations. */
public final class Functions {
  private Functions() {
  }

  /** Create a function from the matterhorn-fn module from a common function. */
  public static  Fn fn(final Function f) {
    return new Fn() {
      @Override
      public B apply(A a) {
        return f.apply(a);
      }
    };
  }

  /** Function composition: f . g = f(g(x)) = o(f, g) */
  public static  Function o(final Function f,
          final Function g) {
    return new Function() {
      @Override
      public C apply(A a) {
        return f.apply(g.apply(a));
      }
    };
  }

  /** Function composition: f . g = f(g) = o(f, g) */
  public static  Function0 o(final Function f, final Function0 g) {
    return new Function0() {
      @Override
      public B apply() {
        return f.apply(g.apply());
      }
    };
  }

  /** f . g . h */
  public static  Function o(final Function f,
          final Function g, final Function h) {
    return new Function() {
      @Override
      public D apply(A a) {
        return f.apply(g.apply(h.apply(a)));
      }
    };
  }

  /** f . g . h . i */
  public static  Function o(final Function f,
          final Function g, final Function h,
          final Function i) {
    return new Function() {
      @Override
      public E apply(A a) {
        return f.apply(g.apply(h.apply(i.apply(a))));
      }
    };
  }

  /** Multiple `then` concatenation. f1 then f2 then ... fn */
  public static  Function concat(final Function... fs) {
    return new Function() {
      @Override
      public A apply(A a) {
        A dc = a;
        for (Function f : fs) {
          dc = f.apply(dc);
        }
        return dc;
      }
    };
  }

  /** Left to right composition: f then g = g(f(x)) */
  public static  Function then(final Function f,
          final Function g) {
    return new Function() {
      @Override
      public C apply(A a) {
        return g.apply(f.apply(a));
      }
    };
  }

  /** Left to right composition: f then g = g(f) */
  public static  Function0 then(final Function0 f, final Function g) {
    return new Function0() {
      @Override
      public B apply() {
        return g.apply(f.apply());
      }
    };
  }

  /** Apply f and ignore its result, then apply g. */
  public static  Function0 then(final Function0 f, final Function0 g) {
    return new Function0() {
      @Override
      public B apply() {
        f.apply();
        return g.apply();
      }
    };
  }

  /**
   * Create a new function from f decorated with an exception transformer. Any exception that occurs during
   * application of f is passed to transformer whose return value is then being thrown.
   */
  public static  Function rethrow(final Function f,
          final Function transformer) {
    return new Function() {
      @Override
      public B apply(A a) {
        try {
          return f.apply(a);
        } catch (Exception e) {
          return chuck(transformer.apply(e));
        }
      }
    };
  }

  /**
   * Create a new function from f decorated with an exception handler. Any exception that occurs during
   * application of f is passed to handler whose return value is then being returned.
   */
  public static  Function handle(final Function f,
          final Function handler) {
    return new Function() {
      @Override
      public B apply(A a) {
        try {
          return f.apply(a);
        } catch (Exception e) {
          return handler.apply(e);
        }
      }
    };
  }

  /**
   * Create a new function from f decorated with an exception handler. The new function either returns the
   * value of f or in case of an exception being thrown on the application of f the return
   * value of handler.
   */
  public static  Function> either(final Function f,
          final Function handler) {
    return new Function>() {
      @Override
      public Either apply(A a) {
        try {
          B b = f.apply(a);
          return right(b);
        } catch (Exception e) {
          C c = handler.apply(e);
          return left(c);
        }
      }
    };
  }

  /** Curry a function of arity 2. */
  // todo rename since its actually partial application
  public static  Function curry(final Function2 f, final A a) {
    return new Function() {
      @Override
      public C apply(B b) {
        return f.apply(a, b);
      }
    };
  }

  /** Curry a function of arity 2. (a, b) -gt; c =gt; a -gt; b -gt; c */
  public static  Function> curry(final Function2 f) {
    return new Function>() {
      @Override
      public Function apply(final A a) {
        return new Function() {
          @Override
          public C apply(B b) {
            return f.apply(a, b);
          }
        };
      }
    };
  }

  /** Uncurry to a function of arity 2. a -gt; b -gt; c =gt; (a, b) -gt; c */
  public static  Function2 uncurry(final Function> f) {
    return new Function2() {
      @Override
      public C apply(A a, B b) {
        return f.apply(a).apply(b);
      }
    };
  }

  /** Curry a function of arity 1. */
  public static  Function0 curry(final Function f, final A a) {
    return new Function0() {
      @Override
      public B apply() {
        return f.apply(a);
      }
    };
  }

  /** Curry a function of arity 1. */
  public static  Function> curry(final Function f) {
    return new Function>() {
      @Override
      public Function0 apply(final A a) {
        return new Function0() {
          @Override
          public B apply() {
            return f.apply(a);
          }
        };
      }
    };
  }

  /** Create a tupled version of a function of arity 2. */
  public static  Function, C> tupled(final Function2 f) {
    return new Function, C>() {
      @Override
      public C apply(Tuple t) {
        return f.apply(t.getA(), t.getB());
      }
    };
  }

  /** Flip arguments of a function of arity 2. */
  public static  Function2 flip(final Function2 f) {
    return new Function2() {
      @Override
      public C apply(B b, A a) {
        return f.apply(a, b);
      }
    };
  }

  /** Turn a function of arity 0 into an effect by discarding its result. */
  public static  Effect0 toEffect(final Function0 f) {
    return new Effect0() {
      @Override
      protected void run() {
        f.apply();
      }
    };
  }

  /** Turn a function into an effect by discarding its result. */
  public static  Effect toEffect(final Function f) {
    return new Effect() {
      @Override
      protected void run(A a) {
        f.apply(a);
      }
    };
  }

  /** Turn a function of arity 2 into an effect by discarding its result. */
  public static  Effect2 toEffect(final Function2 f) {
    return new Effect2() {
      @Override
      protected void run(A a, B b) {
        f.apply(a, b);
      }
    };
  }

  public static  Predicate toPredicate(final Function f) {
    return new Predicate() {
      @Override
      public Boolean apply(A a) {
        return f.apply(a);
      }
    };
  }

  /** Noop effect. */
  public static final Effect0 noop = new Effect0() {
    @Override
    protected void run() {
    }
  };

  /** Noop effect. */
  public static  Effect noop() {
    return new Effect() {
      @Override
      protected void run(A a) {
      }
    };
  }

  /** Identity function. */
  public static  Function identity() {
    return new Function() {
      @Override
      public A apply(A a) {
        return a;
      }
    };
  }

  /**
   * Identity function. The type is based on the type of the example object to save some nasty typing, e.g.
   * Function.<Integer>identity() vs. identity(0)
   *
   * Please note that this constructor is only due to Java's insufficient type inference.
   */
  public static  Function identity(A example) {
    return identity();
  }

  /**
   * Identity function.
   *
   * @param clazz
   *          to describe the functions's type
   */
  public static  Function identity(Class clazz) {
    return identity();
  }

  /** Constant function that always returns a. */
  public static  Function0 constant0(final A a) {
    return new Function0() {
      @Override
      public A apply() {
        return a;
      }
    };
  }

  /** Constant function that always returns b. */
  public static  Function constant(final B b) {
    return new Function() {
      @Override
      public B apply(A ignore) {
        return b;
      }
    };
  }

  /** Constant function that ignores its argument and always returns a. */
  public static  Function ignore(final B b) {
    return new Function() {
      @Override
      public B apply(A a) {
        return b;
      }
    };
  }

  /** Promote function a -> b to an {@link Option}. */
  public static  Function, Option> liftOpt(final Function f) {
    return new Function, Option>() {
      @Override
      public Option apply(Option a) {
        return a.fmap(f);
      }
    };
  }

  /** Promote effect a -> () to an {@link Option}. */
  public static  Function, Option> liftOpt(final Effect f) {
    return new Function, Option>() {
      @Override
      public Option apply(Option a) {
        for (A x : a)
          f.apply(x);
        return a;
      }
    };
  }

  /** Create a bound version of f for {@link Option}. */
  public static  Function, Option> bindOpt(final Function> f) {
    return new Function, Option>() {
      @Override
      public Option apply(Option a) {
        return a.bind(f);
      }
    };
  }

  /** Promote function a -> b to a {@link List}. */
  public static  Function, List> liftList(final Function f) {
    return new Function, List>() {
      @Override
      public List apply(List as) {
        return mlist(as).fmap(f).value();
      }
    };
  }

  /** Create a bound version of f for {@link List}. */
  public static  Function, List> bind(final Function> f) {
    return new Function, List>() {
      @Override
      public List apply(List as) {
        return mlist(as).bind(f).value();
      }
    };
  }

  /** Create an effect that runs its argument. */
  public static final Effect run = new Effect() {
    @Override
    protected void run(Effect0 e) {
      e.apply();
    }
  };

  /** Create an effect that runs its argument passing in a. */
  public static  Effect> run(final A a) {
    return new Effect>() {
      @Override
      protected void run(Effect e) {
        e.apply(a);
      }
    };
  }

  /** Create an effect that runs all given effects in order. */
  public static Effect0 all(final Effect0... es) {
    return new Effect0() {
      @Override
      protected void run() {
        mlist(es).each(run);
      }
    };
  }

  /** Create an effect that runs all given effects in order. */
  public static  Effect all(final Effect... es) {
    return new Effect() {
      @Override
      protected void run(A a) {
        for (Effect e : es) {
          e.apply(a);
        }
      }
    };
  }

  /** Pure functions are covariant in their result type. */
  public static  Function co(Function f) {
    return (Function) f;
  }

  public static  Function, Function> co() {
    return new Function, Function>() {
      @Override
      public Function apply(Function f) {
        return co(f);
      }
    };
  }

  /** Pure functions are contravariant in their argument type. */
  public static  Function contra(Function f) {
    return (Function) f;
  }

  /** Pure functions are covariant in their result type and contravariant in their argument type. */
  public static  Function variant(Function f) {
    return (Function) f;
  }

  private static  A castGeneric(Throwable t) throws T {
    // The cast to T does not happen here but _after_ returning from the method at _assignment_ time
    // But since there is no variable assignment. The Throwable is just thrown.
    throw (T) t;
  }

  /**
   * Throw a checked exception like a RuntimeException removing any needs to declare a throws clause.
   *
   * This technique has been described by James Iry at
   * http://james-iry.blogspot.de/2010/08/on-removing-java-checked-exceptions-by.html
   */
  public static  A chuck(Throwable t) {
    return Functions. castGeneric(t);
  }

  /** Kleisli composition of list monads. (a -> m b) -> (b -> m c) -> a -> m c */
  public static  Function> kleisliCompList(final Function> m,
          final Function> n) {
    return new Function>() {
      @Override
      public List apply(A a) {
        return mlist(m.apply(a)).bind(n).value();
      }
    };
  }

  /** Convert function f into a guava function. */
  public static  com.google.common.base.Function toGuava(final Function f) {
    return new com.google.common.base.Function() {
      @Override
      public B apply(A a) {
        return f.apply(a);
      }
    };
  }

  /** Create a (partial) function from a map. */
  public static  Function> toFn(final Map m) {
    return new Function>() {
      @Override
      public Option apply(A a) {
        B b = m.get(a);
        return option(b);
      }
    };
  }

  /**
   * Treat fs as partial functions. Apply the argument a of the returned function to the
   * functions fs in order unless some value is returned. Return zero if none of the functions
   * is defined at a.
   */
  public static  Function orElse(final B zero, final Function>... fs) {
    return new Function() {
      @Override
      public B apply(A a) {
        for (Function> f : fs) {
          final Option r = f.apply(a);
          if (r.isSome()) {
            return r.get();
          }
        }
        return zero;
      }
    };
  }
}