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

functionalj.function.Func Maven / Gradle / Ivy

There is a newer version: 1.0.17
Show newest version
// ============================================================================
// Copyright (c) 2017-2019 Nawapunth Manusitthipol (NawaMan - http://nawaman.net).
// ----------------------------------------------------------------------------
// MIT License
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ============================================================================
package functionalj.function;

import static java.util.Arrays.stream;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;

import functionalj.environments.Env;
import functionalj.functions.ThrowFuncs;
import functionalj.list.FuncList;
import functionalj.list.ImmutableList;
import functionalj.supportive.CallerId;
import functionalj.tuple.ImmutableTuple2;
import lombok.val;

@SuppressWarnings("javadoc")
public interface Func {
    
    //== Provide different name for more readability ==
    
    /**
     * A shorter way to use Function.identity() -- alias for itself() and themAll().
     * 
     * @param  the type of it.
     * @return the function that take it and return it.
     **/
    public static  Func1 it() {
        return it -> it;
    }
    /**
     * A shorter way to use Function.identity() -- alias for it() and themAll().
     * 
     * @param  the type of it.
     * @return the function that take it and return it.
     **/
    public static  Func1 itself() {
        return it -> it;
    }
    
    /**
     * A shorter way to use Function.identity() -- alias for it() and itself().
     * 
     * @param  the type of it.
     * @return the function that take it and return it.
     **/
    public static  Func1 themAll() {
        return it -> it;
    }
    
    public static  Predicate alwaysTrue() {
        return t -> true;
    }
    public static  Predicate alwaysFalse() {
        return t -> false;
    }
    
    /**
     * A shorter way to do flatmap on list directly.
     * 
     * @param    the input data type.
     * @param   the output data type.
     * @return the function that take list and change to stream.
     */
    public static , OUT> Func1> allLists() {
        return it -> it.stream();
    }
    
    /**
     * A shorter way to do flatmap on list directly from the result of the given mapper function.
     * 
     * @param     the input data type.
     * @param    the output data type.
     * @param mapper  the mapper function.
     * @return the function that will apply the given mapper functio to the input and change the result list to stream.
     */
    public static  Func1> allList(Func1> mapper) {
        return it -> mapper.applyUnsafe(it).stream();
    }
    
    public static  Predicate only(Function check) {
        return input -> check.apply(input);
    }
    
    public static  Predicate only(
            Function      mapper,
            BiPredicate checker,
            I2                  tailInput) {
        return i->checker.test(mapper.apply(i), tailInput);
    }
    
    //== List ==
    
    @SafeVarargs
    public static  FuncList listOf(T ... data) {
        return ImmutableList.of(data);
    }
    
    //== Of ==
    
    /**
     * Constructs a Func0 from supplier or lambda.
     * 
     * @param  supplier  the supplier or lambda.
     * @param    the output data type.
     * @return           the result Func0.
     **/
    public static  
            Func0 of(Func0 supplier) {
        return supplier;
    }
    
    /**
     * Constructs a Func1 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param     the input data type.
     * @param    the output data type.
     * @return           the result Func1.
     **/
    public static  
            Func1 of(Func1 function) {
        return function;
    }
    
    /**
     * Constructs a Func2 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the output data type.
     * @return           the result Func2.
     **/
    public static  
            Func2 of(Func2 function) {
        return function;
    }
    
    /**
     * Constructs a Func3 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static  
            Func3 of(Func3 function) {
        return function;
    }
    
    /**
     * Constructs a Func4 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static
             
            Func4 of(Func4 function) {
        return function;
    }
    
    /**
     * Constructs a Func5 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func5 of(Func5 function) {
        return function;
    }
    
    /**
     * Constructs a Func2 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the sixth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func6 of(Func6 function) {
        return function;
    }
    
    public static  FuncUnit1 of(FuncUnit1 consumer) {
        return FuncUnit1.of(consumer);
    }
    
    public static  FuncUnit2 of(FuncUnit2 consumer) {
        return FuncUnit2.of(consumer);
    }
    
    public static  FuncUnit3 of(FuncUnit3 consumer) {
        return FuncUnit3.of(consumer);
    }
    
    //== From ==
    
    public static FuncUnit0 from(Runnable runnable) {
        if (runnable instanceof FuncUnit0)
            return (FuncUnit0)runnable;
        return runnable::run;
    }
    public static  Predicate from(String name, Predicate predicate) {
        return Named.predicate(name, predicate);
    }
    
    public static  FuncUnit1 from(Consumer consumer) {
        return FuncUnit1.from(consumer);
    }
    
    public static  FuncUnit2 from(BiConsumer consumer) {
        return FuncUnit2.from(consumer);
    }
    /**
     * Constructs a Func0 from supplier or lambda.
     * 
     * @param  supplier  the supplier or lambda.
     * @param    the output data type.
     * @return           the result Func0.
     **/
    public static  Func0 from(Supplier supplier) {
        return Func0.from(supplier);
    }
    
    /**
     * Constructs a Func1 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param     the input data type.
     * @param    the output data type.
     * @return           the result Func1.
     **/
    public static  Func1 from(Function function) {
        return Func1.from(function);
    }
    
    /**
     * Constructs a Func2 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the output data type.
     * @return           the result Func2.
     **/
    public static  Func2 from(BiFunction function) {
        return Func2.from(function);
    }
    
    //== f - no name ==
    
    /**
     * Constructs a Func0 from supplier or lambda.
     * 
     * @param  supplier  the supplier or lambda.
     * @param    the output data type.
     * @return           the result Func0.
     **/
    public static  
            Func0 f(Func0 supplier) {
        return supplier;
    }
    
    /**
     * Constructs a Func1 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param     the input data type.
     * @param    the output data type.
     * @return           the result Func1.
     **/
    public static  
            Func1 f(Func1 function) {
        return function;
    }

    /**
     * Constructs a Func2 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the output data type.
     * @return           the result Func2.
     **/
    public static  
            Func2 f(Func2 function) {
        return function;
    }
    
    /**
     * Constructs a Func3 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static  
            Func3 f(Func3 function) {
        return function;
    }
    
    /**
     * Constructs a Func4 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static
             
            Func4 f(Func4 function) {
        return function;
    }
    
    /**
     * Constructs a Func5 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func5 f(Func5 function) {
        return function;
    }
    
    /**
     * Constructs a Func6 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the sixth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func6 f(Func6 function) {
        return function;
    }
    
    public static FuncUnit0 f(FuncUnit0 runnable) {
        return runnable;
    }
    
    public static  FuncUnit1 f(FuncUnit1 consumer) {
        return consumer;
    }
    
    public static  FuncUnit2 f(FuncUnit2 consumer) {
        return consumer;
    }
    
    //== f - with name ==
    
    /**
     * Constructs a Func0 from supplier or lambda.
     * 
     * @param  supplier  the supplier or lambda.
     * @param    the output data type.
     * @return           the result Func0.
     **/
    public static  
            Func0 f(String name, Func0 function) {
        return Named.func0(name, function);
    }
    
    /**
     * Constructs a Func1 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param     the input data type.
     * @param    the output data type.
     * @return           the result Func1.
     **/
    public static  
            Func1 f(String name, Func1 function) {
        return Named.func1(name, function);
    }

    /**
     * Constructs a Func2 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the output data type.
     * @return           the result Func2.
     **/
    public static  
            Func2 f(String name, Func2 function) {
        return Named.func2(name, function);
    }
    
    /**
     * Constructs a Func3 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static  
            Func3 f(String name, Func3 function) {
        return Named.func3(name, function);
    }
    
    /**
     * Constructs a Func4 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static
             
            Func4 f(String name, Func4 function) {
        return Named.func4(name, function);
    }
    
    /**
     * Constructs a Func5 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func5 f(String name, Func5 function) {
        return Named.func5(name, function);
    }
    
    /**
     * Constructs a Func6 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the sixth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func6 f(String name, Func6 function) {
        return Named.func6(name, function);
    }
    
    public static FuncUnit0 f(String name, FuncUnit0 function) {
        return Named.funcUnit0(name, function);
    }
    
    public static  FuncUnit1 f(String name, FuncUnit1 function) {
        return Named.funcUnit1(name, function);
    }
    
    public static  FuncUnit2 f(String name, FuncUnit2 function) {
        return Named.funcUnit2(name, function);
    }
    
    public static  FuncUnit3 f(String name, FuncUnit3 function) {
        return Named.funcUnit3(name, function);
    }
    
    //== F (traced location) - no name ==
    
    /**
     * Constructs a Func0 from supplier or lambda.
     * 
     * @param  func      the func or lambda.
     * @param    the output data type.
     * @return           the result Func0.
     **/
    public static  
            Func0 F(Func0 function) {
        return CallerId.instance.trace(caller -> Traced.Func0(function));
    }
    
    /**
     * Constructs a Func1 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param     the input data type.
     * @param    the output data type.
     * @return           the result Func1.
     **/
    public static  
            Func1 F(Func1 function) {
        return CallerId.instance.trace(caller -> Traced.Func1(function));
    }

    /**
     * Constructs a Func2 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the output data type.
     * @return           the result Func2.
     **/
    public static  
            Func2 F(Func2 function) {
        return CallerId.instance.trace(caller -> Traced.Func2(function));
    }
    
    /**
     * Constructs a Func3 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static  
            Func3 F(Func3 function) {
        return CallerId.instance.trace(caller -> Traced.Func3(function));
    }
    
    /**
     * Constructs a Func4 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static
             
            Func4 F(Func4 function) {
        return CallerId.instance.trace(caller -> Traced.Func4(function));
    }
    
    /**
     * Constructs a Func5 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func5 F(Func5 function) {
        return CallerId.instance.trace(caller -> Traced.Func5(function));
    }
    
    /**
     * Constructs a Func6 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the sixth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func6 F(Func6 function) {
        return CallerId.instance.trace(caller -> Traced.Func6(function));
    }
    
    public static FuncUnit0 F(FuncUnit0 function) {
        return CallerId.instance.trace(caller -> Traced.FuncUnit0(function));
    }
    
    public static  FuncUnit1 F(FuncUnit1 function) {
        return CallerId.instance.trace(caller -> Traced.FuncUnit1(function));
    }
    
    public static  FuncUnit2 F(FuncUnit2 function) {
        return CallerId.instance.trace(caller -> Traced.FuncUnit2(function));
    }
    
    //== F (traced location) - with name ==
    
    /**
     * Constructs a Func0 from supplier or lambda.
     * 
     * @param  func      the func or lambda.
     * @param    the output data type.
     * @return           the result Func0.
     **/
    public static  
            Func0 F(String name, Func0 function) {
        return CallerId.instance.trace(caller -> Traced.Func0(name, function));
    }
    
    /**
     * Constructs a Func1 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param     the input data type.
     * @param    the output data type.
     * @return           the result Func1.
     **/
    public static  
            Func1 F(String name, Func1 function) {
        return CallerId.instance.trace(caller -> Traced.Func1(name, function));
    }

    /**
     * Constructs a Func2 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the output data type.
     * @return           the result Func2.
     **/
    public static  
            Func2 F(String name, Func2 function) {
        return CallerId.instance.trace(caller -> Traced.Func2(name, function));
    }
    
    /**
     * Constructs a Func3 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static  
            Func3 F(String name, Func3 function) {
        return CallerId.instance.trace(caller -> Traced.Func3(name, function));
    }
    
    /**
     * Constructs a Func4 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static
             
            Func4 F(String name, Func4 function) {
        return CallerId.instance.trace(caller -> Traced.Func4(name, function));
    }
    
    /**
     * Constructs a Func5 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func5 F(String name, Func5 function) {
        return CallerId.instance.trace(caller -> Traced.Func5(name, function));
    }
    
    /**
     * Constructs a Func6 from function or lambda.
     * 
     * @param  function  the function or lambda.
     * @param    the first input data type.
     * @param    the second input data type.
     * @param    the third input data type.
     * @param    the forth input data type.
     * @param    the fifth input data type.
     * @param    the sixth input data type.
     * @param    the output data type.
     * @return           the result Func3.
     **/
    public static 
             
            Func6 F(String name, Func6 function) {
        return CallerId.instance.trace(caller -> Traced.Func6(name, function));
    }
    
    public static FuncUnit0 F(String name, FuncUnit0 function) {
        return CallerId.instance.trace(caller -> Traced.FuncUnit0(name, function));
    }
    
    public static  FuncUnit1 F(String name, FuncUnit1 function) {
        return CallerId.instance.trace(caller -> Traced.FuncUnit1(name, function));
    }
    
    public static  FuncUnit2 F(String name, FuncUnit2 function) {
        return CallerId.instance.trace(caller -> Traced.FuncUnit2(name, function));
    }
    
    //== Elevate (instant bind) ==
    
    public static  Func1 elevate(BiFunction func, I2 input2) {
        return input1 -> Func.applyUnsafe(func, input1, input2);
    }
    
    public static  Func1 elevate(Func3 func, I2 input2, I3 input3) {
        return input1 -> func.apply(input1, input2, input3);
    }
    
    public static  Func1 elevate(Func4 func, I2 input2, I3 input3, I4 input4) {
        return input1 -> func.apply(input1, input2, input3, input4);
    }
    
    public static  Func1 elevate(Func5 func, I2 input2, I3 input3, I4 input4, I5 input5) {
        return input1 -> func.apply(input1, input2, input3, input4, input5);
    }
    
    public static  Func1 elevate(Func6 func, I2 input2, I3 input3, I4 input4, I5 input5, I6 input6) {
        return input1 -> func.apply(input1, input2, input3, input4, input5, input6);
    }
    
    //== Join with delimit ==
    
    public static  Func1> delimitWith(IN delimiter) {
        val isFirst = new AtomicBoolean(true);
        return in -> {
            if (isFirst.getAndSet(false))
                return Stream.of(in);
            return Stream.of(delimiter, in);
        };
    }
    
    public static  Func1> delimitWith(Supplier delimiter) {
        val isFirst = new AtomicBoolean(true);
        return in -> {
            if (isFirst.getAndSet(false))
                return Stream.of(in);
            return Stream.of(delimiter.get(), in);
        };
    }
    
    public static  Func1> delimitWith(Func1 delimiter) {
        val isFirst = new AtomicBoolean(true);
        return in -> {
            if (isFirst.getAndSet(false))
                return Stream.of(in);
            return Stream.of(delimiter.applyUnsafe(in), in);
        };
    }
    
    @SafeVarargs
    public static  Stream streamConcat(Stream ...  streams) {
        return stream(streams)
                .filter(Objects::nonNull)
                .flatMap(themAll());
    }
    
    public static Consumer throwThis(Function exceptionCreator) {
        return errMsg -> {
            if (errMsg == null)
                return;
            
            val exception = exceptionCreator.apply(errMsg);
            if (exception == null)
                return;
            
            throw exception;
        };
    }
    
    //== Index ==
    
    public static  Func1 withIndex(Func2 body) {
        val index = new AtomicInteger();
        return input -> body.applyUnsafe(input, index.getAndIncrement());
    }
    
    public static  Func1 usingIndex(Func1 body) {
        val index = new AtomicInteger();
        return input -> body.applyUnsafe(index.getAndIncrement());
    }
    
    public static class WithIndex extends ImmutableTuple2 {
        public WithIndex(DATA _1, Integer _2) {
            super(_1, _2);
        }
        public int  index() { return _2.intValue(); }
        public DATA value()  { return _1; }
        
        public String toString() {
            // TODO - Umm .. this feels useful but it will break Tuple2.toString() contract.
            return "[#" + _2 + ":" + _1 + "]";
        }
    }
    
    public static interface WithIndexFunction extends Func1, OUTPUT> {
        
    }
    
    public static  Func1 withIndex(WithIndexFunction body) {
        val index = new AtomicInteger();
        return input -> {
            val withIndex = new WithIndex(input, index.getAndIncrement());
            return body.applyUnsafe(withIndex);
        };
    }
    
    public static  Func1> withIndex() {
        val index = new AtomicInteger();
        return input -> new WithIndex(input, index.getAndIncrement());
    }
    
    public static  FuncUnit1 withIndex(FuncUnit2 body) {
        val index = new AtomicInteger();
        return input -> body.acceptUnsafe(input, index.getAndIncrement());
    }
    
    public static  FuncUnit1 withIndex(FuncUnit1 body) {
        val index = new AtomicInteger();
        return input -> body.acceptUnsafe(index.getAndIncrement());
    }
    
    //== Cache and Lazy ==
    
    public static  Func1 cacheFor(Function inFunction) {
        val cache = new ConcurrentHashMap();
        return in -> cache.computeIfAbsent(in, inFunction::apply);
    }
    public static  Func1 cacheFor(long time, Function inFunction) {
        val cache       = new ConcurrentHashMap();
        val expiredTime = new ConcurrentHashMap();
        return in -> {
            if (expiredTime.contains(in)
             && expiredTime.get(in) > Env.time().currentMilliSecond()) {
                cache.remove(in);
            }
            return cache.computeIfAbsent(in, key->{
                expiredTime.put(key, Env.time().currentMilliSecond() + time);
                return inFunction.apply(key);
            });
        };
    }
    
    @SuppressWarnings("unchecked")
    public static  Func0 lazy(Supplier supplier) {
        val reference = new AtomicReference();
        val startKey  = new Object();
        return ()->{
            if (reference.compareAndSet(null, startKey)) {
                try {
                    val value = supplier.get();
                    reference.set((Supplier)(()->value));
                } catch (RuntimeException e) {
                    reference.set(e);
                }
            }
            while (!(reference.get() instanceof Supplier)) {
                if (reference.get() instanceof RuntimeException)
                    throw (RuntimeException)reference.get();
            }
            return ((Supplier)reference.get()).get();
        };
    }
    
    //== Recursive ==
    
    public static  Func1 recusive(Absent absent, I2 i2, Func3, I1, I2, R> func3) {
        Func2 grt = recusive(func3);
        return grt.bind(absent, i2);
    }
    public static  Func1 recusive(I1 i1, Absent absent, Func3, I1, I2, R> func3) {
        Func2 grt = recusive(func3);
        return grt.bind(i1, absent);
    }
    public static  Func1 recusive(Func2, I, R> func2) {
        AtomicReference> selfRef = new AtomicReference<>();
        Supplier> self = selfRef::get;
        Func1 selfFunc = (_i) -> func2.applyUnsafe(self.get(), _i);
        selfRef.set(cacheFor(selfFunc));
        return selfFunc;
    }
    public static  Func2 recusive(
            Func3, I1, I2, R> func3) {
        AtomicReference> selfRef = new AtomicReference<>();
        Supplier> self = selfRef::get;
        Func2 selfFunc = (i1, i2) -> func3.applyUnsafe(self.get(), i1, i2);
        selfRef.set(selfFunc);
        return selfFunc;
    }
    
    //== Apply - Unsafe ==
    
    public static  O applyUnsafe(Function func, I input) throws Exception {
        if (func instanceof Func1)
             return ((Func1)func).applyUnsafe(input);
        else return func.apply(input);
    }
    
    public static  O applyUnsafe(BiFunction func, I1 input1, I2 input2) throws Exception {
        if (func instanceof Func1)
             return ((Func2)func).applyUnsafe(input1, input2);
        else return func.apply(input1, input2);
    }
    
    public static  O getUnsafe(Supplier func) throws Exception {
        if (func instanceof Func1)
             return ((Supplier)func).get();
        else return func.get();
    }
    
    public static void runUnsafe(Runnable runnable) throws Exception {
        if (runnable instanceof Func1)
             ((FuncUnit0)runnable).runUnsafe();
        else runnable.run();
    }
    
    public static  void acceptUnsafe(Consumer func, I input) throws Exception {
        if (func instanceof Func1)
             ((FuncUnit1)func).acceptUnsafe(input);
        else func.accept(input);
    }
    
    public static  void acceptUnsafe(BiConsumer func, I1 input1, I2 input2) throws Exception {
        if (func instanceof Func1)
             ((FuncUnit2)func).acceptUnsafe(input1, input2);
        else func.accept(input1, input2);
    }
    
    //== Apply - Carelessly ==
    
    public static void carelessly(Runnable runnable) {
        if (runnable == null)
            return;
        
        try {
            runnable.run();
        } catch (Exception e) {
            // Do nothing
        }
    }
    
    public static void carelessly(FuncUnit0 action) {
        if (action == null)
            return;
        
        try {
            action.run();
        } catch (Exception e) {
            // Do nothing
        }
    }
    
    public static void gracefully(Runnable runnable) {
        if (runnable == null)
            return;
        
        try {
            runnable.run();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw ThrowFuncs.exceptionTransformer.get().apply(e);
        }
    }
    
    public static void gracefully(FuncUnit0 action) {
        if (action == null)
            return;
        
        try {
            action.run();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw ThrowFuncs.exceptionTransformer.get().apply(e);
        }
    }
    
    //== Instant apply == 
    
    /**
     * Get the value from the supplier that might be null.
     * 
     * @param        the output type.
     * @param        the fallback data type
     * @param supplier  the suppler.
     * @param fallback  the fallback value.
     * @return  the result or the fallback type.
     */
    public static  O getOrElse(Supplier supplier, F fallback) {
        if (supplier == null)
            return fallback;
        
        val value = supplier.get();
        return (value == null) ? fallback : value;
    }
    
    /**
     * Apply the input value to the function that might be null.
     * 
     * @param        the input type.
     * @param        the output type.
     * @param        the fallback data type
     * @param function  the function.
     * @param input     the input value.
     * @param fallback  the fallback value.
     * @return  the result or the fallback type.
     */
    public static  O applyOrElse(Function function, I input, F fallback) {
        if (function == null)
            return fallback;
        
        val value = function.apply(input);
        return (value == null) ? fallback : value;
    }
    
    /**
     * Apply the input value to the function that might be null.
     * 
     * @param       the input 1 type.
     * @param       the input 2 type.
     * @param        the output type.
     * @param        the fallback data type
     * @param function  the function.
     * @param input1    the input 1 value.
     * @param input2    the input 2 value.
     * @param fallback  the fallback value.
     * @return  the result or the fallback type.
     */
    public static  O applyOrElse(
            BiFunction function, 
            I1                                    input1, 
            I2                                    input2,
            F                                     fallback) {
        if (function == null)
            return fallback;
        
        val value = function.apply(input1, input2);
        return (value == null) ? fallback : value;
    }
    
    /**
     * Apply the input value to the function that might be null.
     * 
     * @param       the input 1 type.
     * @param       the input 2 type.
     * @param       the input 3 type.
     * @param        the output type.
     * @param        the fallback data type
     * @param function  the function.
     * @param input1    the input 1 value.
     * @param input2    the input 2 value.
     * @param input3    the input 3 value.
     * @param fallback  the fallback value.
     * @return  the result or the fallback type.
     */
    public static  O applyOrElse(
            Func3 function, 
            I1                                           input1,
            I2                                           input2, 
            I3                                           input3, 
            F                                            fallback) {
        if (function == null)
            return fallback;
        
        return function.apply(input1, input2, input3);
    }
    
    /**
     * Apply the input value to the function that might be null.
     * 
     * @param       the input 1 type.
     * @param       the input 2 type.
     * @param       the input 3 type.
     * @param       the input 4 type.
     * @param        the output type.
     * @param        the fallback data type
     * @param function  the function.
     * @param input1    the input 1 value.
     * @param input2    the input 2 value.
     * @param input3    the input 3 value.
     * @param input4    the input 4 value.
     * @param fallback  the fallback value.
     * @return  the result or the fallback type.
     */
    public static  O applyOrElse(
            Func4 function, 
            I1                                                       input1,
            I2                                                       input2, 
            I3                                                       input3, 
            I4                                                       input4, 
            F                                                        fallback) {
        if (function == null)
            return fallback;
        
        return function.apply(input1, input2, input3, input4);
    }
    
    //== All ==
    
    /**
     * Create a high-order function that will take another function that take the given input and return output.
     * NOTE: Not sure if this a traverse.
     * 
     * @param    the input data type.
     * @param   the output data type.
     * @param input     the input.
     * @return          the high-order function.
     */
    public static  Func1, OUTPUT> allApplyTo(INPUT input) {
        return func -> {
            return func.applyUnsafe(input);
        };
    }
    
    /**
     * Create a high-order function that will take another function that take the given input and return output.
     * NOTE: Not sure if this a traverse.
     * 
     * @param    the input data type.
     * @param input     the input.
     * @return          the high-order function.
     */
    public static  Predicate> allCheckWith(INPUT input) {
        return func -> {
            return func.apply(input);
        };
    }
    
    //== Condition ==
    
    public static  Func1 ifThen(
            Predicate    check, 
            Function then) {
        return input -> {
            if (check.test(input))
                 return Func.applyUnsafe(then, input);
            else return input;
        };
    }
    public static  Func1 ifNotThen(
            Predicate    check, 
            Func1 then) {
        return input -> {
            if (!check.test(input))
                 return Func.applyUnsafe(then, input);
            else return input;
        };
    }
    public static  Func1 ifElse(
            Predicate     check, 
            Function then, 
            Function thenElse) {
        return input -> {
            if (check.test(input))
                 return Func.applyUnsafe(then,     input);
            else return Func.applyUnsafe(thenElse, input);
        };
    }
    
    //== Conversion ==
    
    /**
     * Change the input function to a preficate.
     * 
     * @param  the input type.
     * @param func    the function that takes input and returns boolean.
     * @return the predicate of the same functionality.
     **/
    public static  Predicate toPredicate(Func1 func) {
        return input -> func.apply(input);
    }
    
}