package bjc.data; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.UnaryOperator; import bjc.data.internals.BoundListHolder; import bjc.data.internals.WrappedLazy; import bjc.data.internals.WrappedOption; import bjc.funcdata.FunctionalList; import bjc.funcdata.theory.Functor; /** * A holder of a single value. * * @author ben * * @param * The type of value held. */ public interface Holder 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 Holder bind(Function> binder); /** * Apply an action to the value. * * @param action * The action to apply to the value. */ public default void doWith(final Consumer action) { transform(value -> { action.accept(value); return value; }); } @Override default Function, Functor> fmap(final Function func) { return argumentFunctor -> { if (!(argumentFunctor instanceof Holder)) { final String msg = "This functor only supports mapping over instances of IHolder"; throw new IllegalArgumentException(msg); } final Holder holder = (Holder) 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 Holder makeLazy() { return new WrappedLazy<>(this); } /** * Make this holder a list. * * @return A list version of this holder. */ public default Holder makeList() { return new BoundListHolder<>(new FunctionalList<>(this)); } /** * Make this holder optional. * * @return An optional version of this holder. */ public default Holder 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 Holder map(Function mapper); /** * Replace the held value with a new one. * * @param newValue * The value to hold instead. * * @return The holder itself. */ public default Holder replace(final ContainedType newValue) { return transform(oldValue -> 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 Holder 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); /** * Create an instace of IHolder containing a single value. * * @param The type of the value contained. * * @param contained The value to contain. * * @return An instance of IHolder containing that value. */ static Holder of(ElementType contained) { return new Identity<>(contained); } }