package bjc.utils.data; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.theory.Functor; /** * A holder of a single value. * * @author ben * * @param * The type of value held */ public interface IHolder extends Functor { /** * Bind a function across the value in this container * * @param * The type of value in this container * @param binder * The function to bind to the value * @return A holder from binding the value */ public IHolder bind( Function> binder); /** * Apply an action to the value * * @param action * The action to apply to the value */ public default void doWith(Consumer action) { transform((value) -> { action.accept(value); return value; }); } @Override default Function, Functor> fmap( Function func) { return (argumentFunctor) -> { if (!(argumentFunctor instanceof IHolder)) { throw new IllegalArgumentException( "This functor only supports mapping over instances of IHolder"); } IHolder holder = (IHolder) argumentFunctor; return holder.map(func); }; } @Override public default ContainedType getValue() { return unwrap((value) -> value); } /** * Lifts a function to bind over this holder * * @param * The type of the functions return * @param func * The function to lift over the holder * @return The function lifted over the holder */ public Function> lift( Function func); /** * Make this holder lazy * * @return A lazy version of this holder */ public default IHolder makeLazy() { return new WrappedLazy<>(this); } /** * Make this holder a list * * @return A list version of this holder */ public default IHolder makeList() { return new BoundListHolder<>(new FunctionalList<>(this)); } /** * Make this holder optional * * @return An optional version of this holder */ public default IHolder makeOptional() { return new WrappedOption<>(this); } /** * Create a new holder with a mapped version of the value in this * holder. * * Does not change the internal state of this holder * * @param * The type of the mapped value * @param mapper * The function to do mapping with * @return A holder with the mapped value */ public IHolder map( Function mapper); /** * Replace the held value with a new one * * @param newValue * The value to hold instead * @return The holder itself */ public default IHolder replace(ContainedType newValue) { return transform((oldValue) -> { return newValue; }); } /** * Transform the value held in this holder * * @param transformer * The function to transform the value with * @return The holder itself, for easy chaining */ public IHolder transform( UnaryOperator transformer); /** * Unwrap the value contained in this holder so that it is no longer * held * * @param * The type of the unwrapped value * @param unwrapper * The function to use to unwrap the value * @return The unwrapped held value */ public UnwrappedType unwrap( Function unwrapper); }