/* * esodata - data structures and other things, of varying utility * Copyright 2022, Ben Culkin * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package bjc.functypes; import java.util.*; import java.util.function.*; /** * A source for a value that could produce an exception. * * @author Ben Culkin * * @param The type of value possibly produced. * @param The type of exception possibly thrown. */ @FunctionalInterface public interface Thrower { /** * Attempt to get the value. * * @return The value from this source. * * @throws ExceptionType If something goes wrong getting the value. */ ValueType extract() throws ExceptionType; /** * Converts this thrower into a memoized one. * * Note that if this does throw an exception, it won't be 'memoized' so * that the next call will call this Thrower again. * * @return A memoizing thrower. */ default Thrower memoize() { return new MemoizedThrower<>(this); } /** * Applies a function to the result of this thrower. * * @param The new type output by the function. * * @param func The function to apply. * * @return A thrower that is the result of applying the given function. */ default Thrower bind( Function> func) { return () -> func.apply(extract()).extract(); } /** * Create a thrower that yields a given value. * * @param The type of the value. * * @param val The value to yield. * * @return A thrower that will always yield that value. */ static Thrower from(ValType val) { return () -> val; } /** * Create a thrower that yields a given value. * * @param The type of the value. * * @param val The value to yield. * * @return A thrower that will always yield that value. */ static Thrower from(Supplier val) { return val::get; } /** * Convert a function on values to one over throwers. * * @param The function input type. * @param The function output type. * @param The exception possibly thrown. * * @param func The function to convert. * * @return A function which operates on throwers instead. */ static Function,Thrower> fmap( Function func) { return (input) -> () -> func.apply(input.extract()); } /** * Convert a list of throwers into a thrower that returns a list. * * @param The type output by the thrower. * @param The type of exception thrown. * * @param throwers The list of throwers. * * @return A thrower that returns a list of results. */ static Thrower, ExType> seq(List> throwers) { return () -> { List results = new ArrayList<>(throwers.size()); for (Thrower thrower : throwers) { results.add(thrower.extract()); } return results; }; } /** * Convert a array of throwers into a thrower that returns a list. * * @param The type output by the thrower. * @param The type of exception thrown. * * @param throwers The array of throwers. * * @return A thrower that returns a list of results. */ @SafeVarargs static Thrower, ExType> seq(Thrower... throwers) { return () -> { List results = new ArrayList<>(throwers.length); for (Thrower thrower : throwers) { results.add(thrower.extract()); } return results; }; } } class MemoizedThrower implements Thrower { private final Thrower source; private ValueType val; public MemoizedThrower(Thrower source) { this.source = source; } @Override public ValueType extract() throws ExceptionType { if (val == null) val = source.extract(); return val; } }