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

org.organicdesign.fp.function.Function1 Maven / Gradle / Ivy

// Copyright 2013-12-30 PlanBase Inc. & Glen Peterson
//
// Licensed under the Apache 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://www.apache.org/licenses/LICENSE-2.0
//
// 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.organicdesign.fp.function;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;

import org.organicdesign.fp.Option;
import org.organicdesign.fp.collections.UnmodIterable;
import org.organicdesign.fp.xform.Transformable;
import org.organicdesign.fp.xform.Xform;

/**
 This is like Java 8's java.util.function.Function, but retrofitted to turn checked exceptions
 into unchecked ones.
 */
@FunctionalInterface
public interface Function1 extends Function, Consumer {
    // ========================================== Static ==========================================
    enum Const implements Function1 {
        IDENTITY {
            @Override
            public Object applyEx(Object t) throws Exception {
                return t;
            }

            @SuppressWarnings({"unchecked", "TypeParameterExplicitlyExtendsObject"})
            @Override
            public  Function1 compose(Function1 f) {
                // Composing any function with the identity function has no effect on the original
                // function (by definition of identity) - just return it.
                return (Function1) f;
            }
        }
    }
    enum ConstBool implements Function1 {
        /**
         A predicate that always returns true.  Use accept() for a type-safe version of this predicate.
         */
        ACCEPT {
            @Override public Boolean applyEx (Object ignored) throws Exception {
                return Boolean.TRUE;
            }
        },

        /**
         A predicate that always returns false. Use ConstBool.REJECT for a type-safe version of this predicate.
         */
        REJECT {
            @Override public Boolean applyEx (Object ignored) throws Exception {
                return Boolean.FALSE;
            }
        }
    }

    /** Use {@link Const#IDENTITY} instead. */
    @Deprecated
    Function1 IDENTITY = Const.IDENTITY;

    @SuppressWarnings("unchecked")
    static  Function1 identity() { return (Function1) Const.IDENTITY; }

    static  Function1 or(Function1 a, Function1 b) {
        // Composition is not necessary in every case:
        return a == ConstBool.ACCEPT ? a : // If any are true, all are true.
               a == ConstBool.REJECT ? b : // return whatever b is.
               b == ConstBool.ACCEPT ? b : // If any are true, all are true.
               b == ConstBool.REJECT ? a : // Just amounts to if a else false.
               (S s) -> (a.apply(s) == Boolean.TRUE) || (b.apply(s) == Boolean.TRUE); // compose
    }

    static  Function1 and(Function1 a, Function1 b) {
        // Composition is not necessary in every case:
        return a == ConstBool.ACCEPT ? b : // return whatever b is.
               a == ConstBool.REJECT ? a : // if any are false, all are false.
               b == ConstBool.ACCEPT ? a : // Just amounts to if a else false.
               b == ConstBool.REJECT ? b : // If any are false, all are false.
               (S s) -> (a.apply(s) == Boolean.TRUE) && (b.apply(s) == Boolean.TRUE); // compose
    }

    static  Function1 negate(Function1 a) {
        return a == ConstBool.ACCEPT ? reject() :
               a == ConstBool.REJECT ? accept() :
               (S s) -> (a.apply(s) == Boolean.TRUE) ? Boolean.FALSE : Boolean.TRUE;
    }

    /** Use {@link ConstBool#ACCEPT} instead */
    @Deprecated
    Function1 ACCEPT = ConstBool.ACCEPT;

    /** Use {@link ConstBool#REJECT} instead */
    @Deprecated
    Function1 REJECT = ConstBool.REJECT;

    /** Returns a type-safe version of the ConstBool.ACCEPT predicate. */
    @SuppressWarnings("unchecked")
    static  Function1 accept() { return (Function1) ConstBool.ACCEPT; }

    /** Returns a type-safe version of the ConstBool.REJECT predicate. */
    @SuppressWarnings("unchecked")
    static  Function1 reject() { return (Function1) ConstBool.REJECT; }

    /**
     Composes multiple functions into a single function to potentially minimize trips through
     the source data.  The resultant function will loop through the functions for each item in the
     source.  For a few functions and many source items, that takes less memory.  Considers no
     function to mean the IDENTITY function.  This decision is based on the way filters work and
     may or may not prove useful in practice.  Please use the identity()/IDENTITY
     sentinel value in this abstract class since function comparison is done by reference.

     LIMITATION: You could have a function that maps from T to U then the next from U to V, the
     next from V to W and so on.  So long as the output type of one matches up to the input type of
     the next, you're golden.  But type safety curls up and dies when you try to detect the
     IDENTITY function at some point in the chain.

     For arbitrary chaining, it's best to roll your own.  The following example shows how simple it
     is to chain two functions with an intermediate type into a single composite function:

     

     public static <A,B,C> Function1<A,C> chain2(final Function1<A,B> f1,
                                                             final Function1<B,C> f2) {
         return new Function1<A,C>() {
             @Override
             public C applyEx(A a) throws Exception {
                 return f2.applyEx(f1.applyEx(a));
             }
         };
     }
Even with 2 arguments, there are several signatures that would work: imagine where A=B, B=C, or A=C. I just don't see the value to providing a bunch of chain2(), chain3() etc. functions that will ultimately not be type-safe and cannot perform optimizations for you, when you can roll your own type safe versions as you need them. Only the simplest case seems worth providing, along the lines of the and() helper function in Filter() @param in the functions to applyEx in order. Nulls and IDENTITY functions are ignored. No functions means IDENTITY. @param the type of object to chain functions on @return a function which applies all the given functions in order. */ static Function1 compose(Iterable> in) { if (in == null) { return identity(); } final List> out = new ArrayList<>(); for (Function1 f : in) { if ((f == null) || (f == Const.IDENTITY)) { continue; } out.add(f); } if (out.size() < 1) { return identity(); // No functions means to return the original item } else if (out.size() == 1) { return out.get(0); } else { return v -> { V ret = v; for (Function1 f : out) { ret = f.applyEx(ret); } return ret; }; } } /** Composes multiple predicates into a single predicate to potentially minimize trips through the source data. The resultant predicate will loop through the predicates for each item in the source, but for few predicates and many source items, that takes less memory. Considers no predicate to mean "accept all." Use only accept()/ACCEPT and reject()/REJECT since function comparison is done by reference. @param in the predicates to test in order. Nulls and ACCEPT predicates are ignored. Any REJECT predicate will cause this entire method to return a single REJECT predicate. No predicates means ACCEPT. @param the type of object to predicate on. @return a predicate which returns true if all input predicates return true, false otherwise. */ static Function1 and(Iterable> in) { if (in == null) { return accept(); } Transformable> v = (in instanceof UnmodIterable) ? (UnmodIterable>) in : Xform.of(in); return v.filter(p -> (p != null) && (p != ConstBool.ACCEPT)) .foldLeft(accept(), (accum, p) -> (p == reject()) ? p : and(accum, p), accum -> accum == reject()); } /** Composes multiple predicates into a single predicate to potentially minimize trips through the source data. The resultant predicate will loop through the predicates for each item in the source, but for few predicates and many source items, that takes less memory. Considers no predicate to mean "reject all." Use only accept()/ConstBool.ACCEPT and ConstBool.REJECT since function comparison is done by reference. @param in the predicates to test in order. Nulls and ConstBool.REJECT predicates are ignored. Any ACCEPT predicate will cause this entire method to return the ACCEPT predicate. No predicates means ConstBool.REJECT. @param the type of object to predicate on. @return a predicate which returns true if any of the input predicates return true, false otherwise. */ static Function1 or(Iterable> in) { if (in == null) { return reject(); } Transformable> v = (in instanceof UnmodIterable) ? (UnmodIterable>) in : Xform.of(in); return v.filter(p -> (p != null) && (p != ConstBool.REJECT)) .foldLeft(reject(), (accum, p) -> (p == ConstBool.ACCEPT) ? p : or(accum, p), accum -> accum == ConstBool.ACCEPT); } enum BooleanCombiner { AND { @Override public Function1 combine(Iterable> in) { return and(in); } }, OR { @Override public Function1 combine(Iterable> in) { return or(in); } }; public abstract Function1 combine(Iterable> in); } /** Use only on pure functions with no side effects. Wrap an expensive function with this and for each input value, the output will only be computed once. Subsequent calls with the same input will return identical output very quickly. Please note that the return values from f need to implement equals() and hashCode() correctly for this to work correctly and quickly. */ static Function1 memoize(Function1 f) { return new Function1() { private final Map> memo = new HashMap<>(); @Override public synchronized B applyEx(A a) throws Exception { Option val = memo.get(a); if ( (val != null) && val.isSome() ) { return val.get(); } B ret = f.apply(a); memo.put(a, Option.of(ret)); return ret; } }; } // ========================================= Instance ========================================= /** Implement this one method and you don't have to worry about checked exceptions. */ U applyEx(T t) throws Exception; /** Call this convenience method so that you don't have to worry about checked exceptions. */ @Override default U apply(T t) { try { return applyEx(t); } catch (RuntimeException re) { throw re; } catch (Exception e) { throw new RuntimeException(e); } } /** For compatibility with java.util.function.Consumer. Just a wrapper around apply(). */ @Override default void accept(T t) { apply(t); } @SuppressWarnings("unchecked") default Function1 compose(final Function1 f) { if (f == Const.IDENTITY) { // This violates type safety, but makes sense - composing any function with the // identity function should return the original function unchanged. If you mess up the // types, then that's your problem. With generics and type erasure this may be the // best you can do. return (Function1) this; } final Function1 parent = this; return s -> parent.applyEx(f.applyEx(s)); } }