diff options
55 files changed, 1292 insertions, 128 deletions
diff --git a/src/main/java/bjc/data/BooleanToggle.java b/src/main/java/bjc/data/BooleanToggle.java index 56cbdf0..41f2564 100644 --- a/src/main/java/bjc/data/BooleanToggle.java +++ b/src/main/java/bjc/data/BooleanToggle.java @@ -83,7 +83,7 @@ public class BooleanToggle implements Toggle<Boolean> { final BooleanToggle other = (BooleanToggle) obj; if (val != other.val) return false; - else return true; + return true; } @Override diff --git a/src/main/java/bjc/data/Either.java b/src/main/java/bjc/data/Either.java index 42d2e99..07845f6 100644 --- a/src/main/java/bjc/data/Either.java +++ b/src/main/java/bjc/data/Either.java @@ -185,6 +185,14 @@ public class Either<LeftType, RightType> { return rightVal; } + /** + * Change the type of the right-side of this either. + * + * Works only for left Eithers. + * + * @param <T> The new type for the right side + * @return The either with the new type. + */ @SuppressWarnings("unchecked") public <T> Either<LeftType, T> newRight() { if (isLeft) return (Either<LeftType, T>) this; @@ -192,6 +200,14 @@ public class Either<LeftType, RightType> { throw new NoSuchElementException("Can't replace right type on right Either"); } + /** + * Change the type of the left-side of this either. + * + * Works only for right Eithers. + * + * @param <T> The new type for the left side + * @return The either with the new type. + */ @SuppressWarnings("unchecked") public <T> Either<T, RightType> newLeft() { if (isLeft) @@ -199,6 +215,14 @@ public class Either<LeftType, RightType> { return (Either<T, RightType>) this; } + /** + * Collapse an Either with the same type on both sides. + * + * @param <T> The type of the either + * @param eth The either to collapse + * + * @return The collapsed either + */ public static <T> T collapse(Either<T, T> eth) { return eth.extract(ID.id(), ID.id()); } diff --git a/src/main/java/bjc/data/Lazy.java b/src/main/java/bjc/data/Lazy.java index 45293e2..436e4c3 100644 --- a/src/main/java/bjc/data/Lazy.java +++ b/src/main/java/bjc/data/Lazy.java @@ -87,10 +87,7 @@ public class Lazy<ContainedType> implements Holder<ContainedType> { } - final Supplier<ContainedType> supplier = () -> { - if (valueMaterialized) return heldValue; - else return valueSupplier.get(); - }; + final Supplier<ContainedType> supplier = () -> valueMaterialized ? heldValue : valueSupplier.get(); return new BoundLazy<>(() -> new Lazy<>(supplier, pendingActions), binder); } @@ -128,18 +125,18 @@ public class Lazy<ContainedType> implements Holder<ContainedType> { if (valueMaterialized) { if (actions.isEmpty()) { return String.format("value[v='%s']", heldValue); - } else { - return String.format("value[v='%s'] (has %d pending transforms)", - heldValue, actions.getSize()); } + + return String.format("value[v='%s'] (has %d pending transforms)", + heldValue, actions.getSize()); } if (actions.isEmpty()) { return"(unmaterialized)"; - } else { - return String.format("(unmaterialized; has %d pending transforms", - actions.getSize()); } + + return String.format("(unmaterialized; has %d pending transforms", + actions.getSize()); } @Override diff --git a/src/main/java/bjc/data/OneWayToggle.java b/src/main/java/bjc/data/OneWayToggle.java index 0705344..c427af3 100644 --- a/src/main/java/bjc/data/OneWayToggle.java +++ b/src/main/java/bjc/data/OneWayToggle.java @@ -57,8 +57,7 @@ public class OneWayToggle<E> implements Toggle<E> { @Override public E peek() { - if (gotFirst) return second; - else return first; + return gotFirst ? second : first; } @Override diff --git a/src/main/java/bjc/data/Pair.java b/src/main/java/bjc/data/Pair.java index fe65936..dd6ff7c 100644 --- a/src/main/java/bjc/data/Pair.java +++ b/src/main/java/bjc/data/Pair.java @@ -268,6 +268,15 @@ public interface Pair<LeftType, RightType> extends Bifunctor<LeftType, RightType return new SimplePair<>(left, right); } + /** + * Swap the left & right sides of this pair + * + * @return The pair with the left and right types swapped + */ + public default Pair<RightType, LeftType> swap() { + return merge((l, r) -> Pair.pair(r, l)); + } + @Override default void formatTo(Formatter formatter, int flags, int width, int precision) { if ((flags & FormattableFlags.ALTERNATE) != 0) { diff --git a/src/main/java/bjc/data/PetriNet.java b/src/main/java/bjc/data/PetriNet.java index b4c08e1..2dea6d6 100644 --- a/src/main/java/bjc/data/PetriNet.java +++ b/src/main/java/bjc/data/PetriNet.java @@ -31,11 +31,19 @@ public class PetriNet<Label> { private Map<Label, Integer> nodes; private Map<Label, PetriTransition<Label>> transitions; + /** + * Create a new Petri net + */ public PetriNet() { nodes = new HashMap<>(); transitions = new HashMap<>(); } + /** + * Merge this Petri net for another. + * + * @param net The other Petri net. + */ public void merge(PetriNet<Label> net) { for (Entry<Label, Integer> node : net.nodes.entrySet()) { int value = node.getValue(); @@ -50,6 +58,15 @@ public class PetriNet<Label> { } } + /** + * Create a Petri net from merging others. + * + * @param <Label> The type of the labels in the Petri net + * @param nets The nets to merge + * + * @return A net formed by merging all of the provided ones. + */ + @SafeVarargs public static <Label> PetriNet<Label> merged(PetriNet<Label>... nets) { PetriNet<Label> result = new PetriNet<>(); diff --git a/src/main/java/bjc/data/PetriTransition.java b/src/main/java/bjc/data/PetriTransition.java index 79f879d..6aba5a5 100644 --- a/src/main/java/bjc/data/PetriTransition.java +++ b/src/main/java/bjc/data/PetriTransition.java @@ -20,12 +20,22 @@ package bjc.data; import java.util.*; import java.util.Map.Entry; +/** + * Represents a transition in a Petri net + * @author bjcul + * + * @param <Label> The type of the label + */ public class PetriTransition<Label> { private final Label name; private Map<Label, Integer> sources; private Map<Label, Integer> destinations; + /** + * Create a new transition + * @param name The name for this transition + */ public PetriTransition(Label name) { this.name = name; @@ -33,22 +43,54 @@ public class PetriTransition<Label> { destinations = new HashMap<>(); } + /** + * Add a source to this transition + * + * @param lab The label to move from + * @param tokens The number of tokens to move + */ public void addSource(Label lab, int tokens) { sources.merge(lab, tokens, (k, v) -> v + tokens); } + /** + * Remove a source from this transition + * + * @param lab The source to remove + * @return The number of tokens that would've been moved + */ public int removeSource(Label lab) { return sources.remove(lab); } + /** + * Add a destination to this transition. + * + * @param lab The label for the destination + * @param tokens The number of tokens to add + */ public void addDestination(Label lab, int tokens) { destinations.merge(lab, tokens, (k, v) -> v + tokens); } - public int removeDestination(Label lab, int tokens) { + /** + * Remove a destination from this transition + * + * @param lab The destination to remove + * + * @return The number of tokens which would've moved + */ + public int removeDestination(Label lab) { return destinations.remove(lab); } + /** + * Apply this transition to a map + * + * @param nodes The map to apply the transition to + * + * @return Whether the transition was successfully applied. + */ public boolean apply(Map<Label, Integer> nodes) { Set<Entry<Label, Integer>> debts = new HashSet<>(); boolean failed = false; @@ -100,6 +142,11 @@ public class PetriTransition<Label> { return true; } + /** + * Merge this transition with another one + * + * @param transition The transition to merge + */ public void merge(PetriTransition<Label> transition) { for (Entry<Label, Integer> source : transition.sources.entrySet()) { int val = source.getValue(); @@ -133,6 +180,16 @@ public class PetriTransition<Label> { && Objects.equals(sources, other.sources); } + /** + * Create a transition from merging a bunch + * + * @param <Label> The type of the label + * + * @param mergeName The label for the merged transition + * @param transitions The transitions to merge + * + * @return A transition created by merging the given ones + */ @SafeVarargs public static <Label> PetriTransition<Label> merged(Label mergeName, PetriTransition<Label>... transitions) { PetriTransition<Label> result = new PetriTransition<>(mergeName); diff --git a/src/main/java/bjc/data/Triple.java b/src/main/java/bjc/data/Triple.java new file mode 100644 index 0000000..296a169 --- /dev/null +++ b/src/main/java/bjc/data/Triple.java @@ -0,0 +1,78 @@ +package bjc.data; + +/** + * Represents a tuple of three values + * @author bjcul + * + * @param <Left> The type of the first value + * @param <Middle> The type of the second value + * @param <Right> The type of the third value + */ +public interface Triple<Left, Middle, Right> { + // TODO: fill this out more; mapping and the like + /** + * Get the left value for this triple. + * + * @return The left value for this triple. + */ + public Left left(); + + /** + * Get the right value for this triple. + * + * @return The right value for this triple. + */ + public Right right(); + + /** + * Get the middle value for this triple. + * + * @return The middle value for this triple. + */ + public Middle middle(); + + /** + * Create a new triple + * + * @param <Left> The type for the left + * @param <Middle> The type for the middle + * @param <Right> The type for the right + * + * @param l The left value + * @param m The middle value + * @param r The right value + * + * @return A triple of the given values + */ + public static <Left, Middle, Right> Triple<Left, Middle, Right> of(Left l, Middle m, Right r) { + return new SimpleTriple<>(r, m, l); + } +} + +final class SimpleTriple<Left, Middle, Right> implements Triple<Left, Middle, Right> { + private final Right r; + private final Middle m; + private final Left l; + + SimpleTriple(Right r, Middle m, Left l) { + this.r = r; + this.m = m; + this.l = l; + } + + + @Override + public Left left() { + return l; + } + + @Override + public Right right() { + return r; + } + + @Override + public Middle middle() { + return m; + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/data/ValueToggle.java b/src/main/java/bjc/data/ValueToggle.java index 4e9f7c0..4e72fa6 100644 --- a/src/main/java/bjc/data/ValueToggle.java +++ b/src/main/java/bjc/data/ValueToggle.java @@ -54,14 +54,12 @@ public class ValueToggle<E> implements Toggle<E> { @Override public E get() { - if (alignment.get()) return lft; - else return rght; + return alignment.get() ? lft : rght; } @Override public E peek() { - if (alignment.peek()) return lft; - else return rght; + return alignment.peek() ? lft : rght; } @Override diff --git a/src/main/java/bjc/esodata/AbbrevMap2.java b/src/main/java/bjc/esodata/AbbrevMap2.java index 72bd4c8..6605c17 100644 --- a/src/main/java/bjc/esodata/AbbrevMap2.java +++ b/src/main/java/bjc/esodata/AbbrevMap2.java @@ -18,6 +18,7 @@ package bjc.esodata; import java.util.*; +import java.util.function.Function; /** * A map that allows you to reference strings by unambiguous abbreviations to @@ -34,18 +35,65 @@ import java.util.*; * @author Ben Culkin */ public class AbbrevMap2 { + /** + * Strategy to generate abbreviations for an AbbrevMap. + * @author bjcul + * + */ + public static interface AbbrevStrategy extends Function<String, List<String>>{ + // alias iface. + } + // Stores a mapping from strings, to strings that they could be abbreviations // for private Multimap<String, String> backing; + private List<AbbrevStrategy> strategies; + + /** + * Strategy which generates abbreviations as all of the prefixes of a word + */ + public static final AbbrevStrategy INITIAL = (word) -> { + List<String> retList = new ArrayList<>(); + + int len = word.length(); + + for (int i = 1; i <= len; i++) { + String substr = word.substring(0, i); + + retList.add(substr); + } + + return retList; + }; + + /** + * Strategy which converts a camel-case word into the letters of its components. + */ + public static final AbbrevStrategy CAMELCASE = (word) -> { + List<String> retList = new ArrayList<>(); + // TODO implement a thing + return retList; + }; + /** * Create a new abbreviation map. */ public AbbrevMap2() { - backing = new TSetMultimap<>(); + this(INITIAL); } /** + * Create a new abbreviation map. + * + * @param strategies The strategies to use to generate abbreviations. + */ + public AbbrevMap2(AbbrevStrategy... strategies) { + this.backing = new TSetMultimap<>(); + this.strategies = List.of(strategies); + } + + /** * Add words to the map. * * @param words @@ -58,15 +106,11 @@ public class AbbrevMap2 { } // Generate all of the strings a given word could be abbreviated as - private static List<String> genAbbrevs(String word) { + private List<String> genAbbrevs(String word) { List<String> retList = new ArrayList<>(); - int len = word.length(); - - for (int i = 1; i <= len; i++) { - String substr = word.substring(0, i); - - retList.add(substr); + for (AbbrevStrategy strategy : strategies) { + retList.addAll(strategy.apply(word)); } return retList; @@ -88,9 +132,9 @@ public class AbbrevMap2 { * Get all of the strings that a string could be an abbreviation for. * * @param word - * The word to attempt to deabbreviate. + * The word to attempt to de-abbreviate. * - * @return All of the possible deabbreviations for that word. + * @return All of the possible de-abbreviations for that word. */ public Set<String> deabbrevAll(String word) { return backing.get(word); @@ -100,15 +144,16 @@ public class AbbrevMap2 { * Get the unambiguous thing the string is an abbreviation for. * * @param word - * The word to attempt to deabbreviate. + * The word to attempt to de-abbreviate. * - * @return The unambiguous deabbreviation of the string, or null if there isn't + * @return The unambiguous de-abbreviation of the string, or null if there isn't * one. */ public String deabbrev(String word) { Set<String> st = backing.get(word); if (st.size() == 1) return st.iterator().next(); - else return null; + + return null; } } diff --git a/src/main/java/bjc/esodata/ClosedSpoolException.java b/src/main/java/bjc/esodata/ClosedSpoolException.java new file mode 100644 index 0000000..ed94222 --- /dev/null +++ b/src/main/java/bjc/esodata/ClosedSpoolException.java @@ -0,0 +1,48 @@ +package bjc.esodata; + +/** + * Exception thrown for attempting to do something with a closed spool that you + * should not have. + * + * @author bjcul + * + */ +public class ClosedSpoolException extends RuntimeException { + private static final long serialVersionUID = 2846671972910718257L; + + /** + * Create a new default closed spool exception + */ + public ClosedSpoolException() { + super(); + } + + /** + * Create a new closed spool exception with a given message and cause. + * + * @param message The message for the exception. + * @param cause The cause of the exception. + */ + public ClosedSpoolException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Create a new closed spool exception with a given message. + * + * @param message The message for the exception + */ + public ClosedSpoolException(String message) { + super(message); + } + + /** + * Create a new closed spool exception with a given cause. + * + * @param cause The cause for the exception. + */ + public ClosedSpoolException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/bjc/esodata/ComplexSpooler.java b/src/main/java/bjc/esodata/ComplexSpooler.java new file mode 100644 index 0000000..095527a --- /dev/null +++ b/src/main/java/bjc/esodata/ComplexSpooler.java @@ -0,0 +1,43 @@ +package bjc.esodata; + +import java.util.*; +import java.util.function.Consumer; + +/** + * Implementation of {@link Spooler} which supports a number of additional features. + * + * @author bjcul + * + * @param <T> The type of data contained on the spools + */ +public class ComplexSpooler<T> implements Spooler<T> { + private Queue<Spool<T>> pendingAnonSpools; + private Map<String, Queue<Spool<T>>> pendingGroupedSpools; + + private Map<String, Spool<T>> labelledSpools; + + @Override + public void registerSpool(Spool<T> spool) { + // TODO Auto-generated method stub + + } + + @Override + public Consumer<T> getInput() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Iterator<T> getOutput() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Spool<T> getSpool() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/main/java/bjc/esodata/DefaultList.java b/src/main/java/bjc/esodata/DefaultList.java index 727eafd..cde6ed4 100644 --- a/src/main/java/bjc/esodata/DefaultList.java +++ b/src/main/java/bjc/esodata/DefaultList.java @@ -108,7 +108,8 @@ public class DefaultList<ValueType> extends AbstractList<ValueType> { @Override public ValueType get(int idx) { if (idx < 0 || idx >= backing.size()) return defVal; - else return backing.get(idx); + + return backing.get(idx); } @Override diff --git a/src/main/java/bjc/esodata/DefaultSpool.java b/src/main/java/bjc/esodata/DefaultSpool.java new file mode 100644 index 0000000..372275d --- /dev/null +++ b/src/main/java/bjc/esodata/DefaultSpool.java @@ -0,0 +1,80 @@ +package bjc.esodata; + +import java.util.Iterator; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.function.Consumer; + +/** + * A default implementation of {@link Spool} using a {@link LinkedBlockingDeque} + * as the backing storage. + * + * @author bjcul + * + * @param <T> The type contained in the spool + */ +public class DefaultSpool<T> implements Spool<T>, AutoCloseable { + private String label; + private String group; + + private BlockingQueue<T> container; + + private boolean closed; + + /** + * Create a new spool without label or group + */ + public DefaultSpool() { + this(null, null); + } + + /** + * Create a new spool with a given label and group. + * + * @param label The label of the spool + * @param group The group for the spool + */ + public DefaultSpool(String label, String group) { + this.label = label; + this.group = group; + + this.container = new LinkedBlockingDeque<>(); + this.closed = false; + } + + @Override + public String label() { + return label; + } + + @Override + public String group() { + return group; + } + + @Override + public Consumer<T> getInput() { + return (val) -> { + if (closed) { + throw new ClosedSpoolException(); + } + container.add(val); + }; + } + + @Override + public Iterator<T> getOutput() { + return container.iterator(); + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public void close() throws Exception { + closed = true; + } + +} diff --git a/src/main/java/bjc/esodata/DefaultSpooler.java b/src/main/java/bjc/esodata/DefaultSpooler.java new file mode 100644 index 0000000..8ac7891 --- /dev/null +++ b/src/main/java/bjc/esodata/DefaultSpooler.java @@ -0,0 +1,43 @@ +package bjc.esodata; + +import java.util.*; +import java.util.function.Consumer; + +/** + * A default implementation of {@link Spooler} that handles spools in a FIFO manner + * @author bjcul + * + * @param <T> The type contained in the spools. + */ +public class DefaultSpooler<T> implements Spooler<T> { + private Queue<Spool<T>> spools; + + /** + * Create a new default spooler. + */ + public DefaultSpooler() { + this.spools = new ArrayDeque<>(); + } + + @Override + public void registerSpool(Spool<T> spool) { + spools.add(spool); + } + + @Override + public Consumer<T> getInput() { + Spool<T> spool = new DefaultSpool<>(); + registerSpool(spool); + return spool.getInput(); + } + + @Override + public Iterator<T> getOutput() { + return spools.remove().getOutput(); + } + + @Override + public Spool<T> getSpool() { + return spools.remove(); + } +} diff --git a/src/main/java/bjc/esodata/KeyedList.java b/src/main/java/bjc/esodata/KeyedList.java index 5b0d6cc..5a381e1 100644 --- a/src/main/java/bjc/esodata/KeyedList.java +++ b/src/main/java/bjc/esodata/KeyedList.java @@ -19,12 +19,23 @@ package bjc.esodata; import java.util.*; +/** + * Implements a keyed list. + * + * @author bjcul + * + * @param <Key> The type of the key + * @param <Val> The type of the value + */ public class KeyedList<Key, Val> implements Iterable<Val> { private List<Val> backing; private Map<Key, Integer> indices; private int currIdx = 0; + /** + * Create a new keyed list + */ public KeyedList() { backing = new ArrayList<>(); indices = new HashMap<>(); diff --git a/src/main/java/bjc/esodata/Multimap.java b/src/main/java/bjc/esodata/Multimap.java index d0c0b4b..e9c19bb 100644 --- a/src/main/java/bjc/esodata/Multimap.java +++ b/src/main/java/bjc/esodata/Multimap.java @@ -97,6 +97,11 @@ public interface Multimap<KeyType, ValueType> { */ boolean contains(KeyType key, ValueType value); + /** + * Retrieve an iterator over the values in this map + * + * @return An iterator over the values in this map + */ Iterator<Pair<KeyType, ValueType>> iterator(); }
\ No newline at end of file diff --git a/src/main/java/bjc/esodata/NestList.java b/src/main/java/bjc/esodata/NestList.java index c1544ca..d45229f 100644 --- a/src/main/java/bjc/esodata/NestList.java +++ b/src/main/java/bjc/esodata/NestList.java @@ -345,10 +345,10 @@ public class NestList<Element> extends AbstractList<Either<Element, NestList<Ele subst.addItem(sublist); } })); - } else { - state.addItem(list); - return state; } + + state.addItem(list); + return state; }); } // List methods and other things. diff --git a/src/main/java/bjc/esodata/PushdownMap.java b/src/main/java/bjc/esodata/PushdownMap.java index a6e153c..e9ff4de 100644 --- a/src/main/java/bjc/esodata/PushdownMap.java +++ b/src/main/java/bjc/esodata/PushdownMap.java @@ -163,9 +163,9 @@ public class PushdownMap<KeyType, ValueType> implements MapEx<KeyType, ValueType if (thawEnabled) { isFrozen = false; return true; - } else { - return false; } + + return false; } @Override diff --git a/src/main/java/bjc/esodata/Spool.java b/src/main/java/bjc/esodata/Spool.java new file mode 100644 index 0000000..f065093 --- /dev/null +++ b/src/main/java/bjc/esodata/Spool.java @@ -0,0 +1,48 @@ +package bjc.esodata; + +import java.util.Iterator; +import java.util.function.Consumer; + +/** + * A single spool, or batch of input. + * + * @author bjcul + * + * @param <T> The type contained by the spool + */ +public interface Spool<T> { + /** + * Get the label that identifies this spool, if it has one. + * + * @return The label of the spool, or null if it is unlabeled. + */ + public String label(); + + /** + * Get the group that this spool belongs to, if it belongs to one. + * + * @return The group the spool is in, or null if it is not in a group. + */ + public String group(); + + /** + * Get a function that will add input to this spool + * + * @return A function that will add input to this spool. + */ + public Consumer<T> getInput(); + + /** + * Get an iterator that will iterate over the data contained in this spool. + * + * @return An iterator over the data in this spool. + */ + public Iterator<T> getOutput(); + + /** + * Is this spool closed, meaning it can accept no more input? + * + * @return Whether the spool is closed + */ + public boolean isClosed(); +}
\ No newline at end of file diff --git a/src/main/java/bjc/esodata/Spooler.java b/src/main/java/bjc/esodata/Spooler.java new file mode 100644 index 0000000..2cf415a --- /dev/null +++ b/src/main/java/bjc/esodata/Spooler.java @@ -0,0 +1,42 @@ +package bjc.esodata; + +import java.util.Iterator; +import java.util.function.Consumer; + +/** + * Represents a 'spool' facility for gathering batches of input together to be + * processed. + * + * @author bjcul + * + * @param <T> The type of data held in the spools + */ +public interface Spooler<T> { + /** + * Register a pre-existing spool with this spooler. + * + * @param spool The spool to register + */ + public void registerSpool(Spool<T> spool); + + /** + * Get a consumer belonging to a new anonymous spool. + * + * @return A new anonymous spool. + */ + public Consumer<T> getInput(); + + /** + * Get the output for a unprocessed spool. + * + * @return The output for a unprocessed spool. + */ + public Iterator<T> getOutput(); + + /** + * Get an unprocessed spool. + * + * @return An unprocessed spool + */ + public Spool<T> getSpool(); +} diff --git a/src/main/java/bjc/esodata/TSetMultimap.java b/src/main/java/bjc/esodata/TSetMultimap.java index 1a04a41..6c925ab 100644 --- a/src/main/java/bjc/esodata/TSetMultimap.java +++ b/src/main/java/bjc/esodata/TSetMultimap.java @@ -94,7 +94,8 @@ public class TSetMultimap<KeyType, ValueType> implements Iterable<Pair<KeyType, @Override public Set<ValueType> get(KeyType key) { if (!backing.containsKey(key)) return new HashSet<>(); - else return backing.get(key).values(); + + return backing.get(key).values(); } @Override diff --git a/src/main/java/bjc/esodata/TapeLibrary.java b/src/main/java/bjc/esodata/TapeLibrary.java index 5fec28a..3794dd5 100644 --- a/src/main/java/bjc/esodata/TapeLibrary.java +++ b/src/main/java/bjc/esodata/TapeLibrary.java @@ -132,9 +132,9 @@ public class TapeLibrary<ElementType> implements TapeView<ElementType> (ignored) -> new SingleTape<>()); return true; - } else { - return false; } + + return false; } /** diff --git a/src/main/java/bjc/esodata/spool/Spool.java b/src/main/java/bjc/esodata/spool/Spool.java deleted file mode 100644 index 80e8a8c..0000000 --- a/src/main/java/bjc/esodata/spool/Spool.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 <https://www.gnu.org/licenses/>. - */ -package bjc.esodata.spool; - -public interface Spool<Contained> { - -} diff --git a/src/main/java/bjc/esodata/spool/Spooler.java b/src/main/java/bjc/esodata/spool/Spooler.java deleted file mode 100644 index 133df2e..0000000 --- a/src/main/java/bjc/esodata/spool/Spooler.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 <https://www.gnu.org/licenses/>. - */ -package bjc.esodata.spool; - -public interface Spooler { - public <E> Spool<E> getSpool(); -} diff --git a/src/main/java/bjc/funcdata/ExtendedMap.java b/src/main/java/bjc/funcdata/ExtendedMap.java index 4bee343..800cfaa 100644 --- a/src/main/java/bjc/funcdata/ExtendedMap.java +++ b/src/main/java/bjc/funcdata/ExtendedMap.java @@ -66,7 +66,8 @@ class ExtendedMap<KeyType, ValueType> implements MapEx<KeyType, ValueType> { @Override public boolean containsKey(final KeyType key) { if (store.containsKey(key)) return true; - else return delegate.containsKey(key); + + return delegate.containsKey(key); } @Override @@ -79,7 +80,8 @@ class ExtendedMap<KeyType, ValueType> implements MapEx<KeyType, ValueType> { @Override public Optional<ValueType> get(final KeyType key) { if (store.containsKey(key)) return store.get(key); - else return delegate.get(key); + + return delegate.get(key); } @Override @@ -111,7 +113,8 @@ class ExtendedMap<KeyType, ValueType> implements MapEx<KeyType, ValueType> { throw new ObjectFrozen("Can't remove key " + key + " from frozen map"); if (!store.containsKey(key)) return delegate.remove(key); - else return store.remove(key); + + return store.remove(key); } @Override @@ -159,9 +162,9 @@ class ExtendedMap<KeyType, ValueType> implements MapEx<KeyType, ValueType> { if (thawEnabled) { isFrozen = false; return true; - } else { - return false; } + + return false; } @Override diff --git a/src/main/java/bjc/funcdata/Freezable.java b/src/main/java/bjc/funcdata/Freezable.java index c337509..c4bd27d 100644 --- a/src/main/java/bjc/funcdata/Freezable.java +++ b/src/main/java/bjc/funcdata/Freezable.java @@ -28,6 +28,7 @@ package bjc.funcdata; * you attempt to modify a frozen object, but they may also choose not to. * * @author Ben Culkin + * @param <F> The type of the implementing object */ public interface Freezable<F extends Freezable<?>> { /** diff --git a/src/main/java/bjc/funcdata/FunctionalMap.java b/src/main/java/bjc/funcdata/FunctionalMap.java index 33a97e6..aec4d28 100644 --- a/src/main/java/bjc/funcdata/FunctionalMap.java +++ b/src/main/java/bjc/funcdata/FunctionalMap.java @@ -95,9 +95,9 @@ public class FunctionalMap<KeyType, ValueType> implements MapEx<KeyType, ValueTy if (wrappedMap.containsKey(key)) { return Optional.of(wrappedMap.get(key)); - } else { - return Optional.empty(); } + + return Optional.empty(); } @Override @@ -172,9 +172,9 @@ public class FunctionalMap<KeyType, ValueType> implements MapEx<KeyType, ValueTy if (thawEnabled) { isFrozen = false; return true; - } else { - return false; } + + return false; } @Override diff --git a/src/main/java/bjc/funcdata/MapEx.java b/src/main/java/bjc/funcdata/MapEx.java index 1dad1dc..b25960a 100644 --- a/src/main/java/bjc/funcdata/MapEx.java +++ b/src/main/java/bjc/funcdata/MapEx.java @@ -31,7 +31,7 @@ import java.util.function.*; * @param <ValueType> * The type of this map's values. */ -public interface MapEx<KeyType, ValueType> extends Freezable { +public interface MapEx<KeyType, ValueType> extends Freezable<MapEx<KeyType, ValueType>> { /** * Execute an action for each entry in the map. * diff --git a/src/main/java/bjc/funcdata/TransformedValueMap.java b/src/main/java/bjc/funcdata/TransformedValueMap.java index 57fe155..cd75f4a 100644 --- a/src/main/java/bjc/funcdata/TransformedValueMap.java +++ b/src/main/java/bjc/funcdata/TransformedValueMap.java @@ -123,9 +123,9 @@ final class TransformedValueMap<OldKey, OldValue, NewValue> if (thawEnabled) { isFrozen = false; return true; - } else { - return false; } + + return false; } @Override diff --git a/src/main/java/bjc/functypes/Combinators.java b/src/main/java/bjc/functypes/Combinators.java index 14af611..ad17975 100644 --- a/src/main/java/bjc/functypes/Combinators.java +++ b/src/main/java/bjc/functypes/Combinators.java @@ -347,4 +347,21 @@ public class Combinators { public static <Input> Consumer<Holder<Input>> mutating(UnaryOperator<Input> f) { return (hld) -> hld.transform(f); } + + /** + * Splat a function so that it is applied to many arguments at once. + * + * @param <Input> The input type + * @param <Output> The output type + * + * @param f The function + * @return A splatted variant of the function + */ + public static <Input, Output> VarArgFunction<Input, Output> splat(Function<Input, Output> f) { + return (vals) -> { + List<Output> ret = new ArrayList<>(vals.length); + for (Input val : vals) ret.add(f.apply(val)); + return ret; + }; + } }
\ No newline at end of file diff --git a/src/main/java/bjc/functypes/Const.java b/src/main/java/bjc/functypes/Const.java index 2fc1606..4c3d498 100644 --- a/src/main/java/bjc/functypes/Const.java +++ b/src/main/java/bjc/functypes/Const.java @@ -2,6 +2,14 @@ package bjc.functypes; import bjc.typeclasses.Container; +/** + * Represents a constant container + * + * @author bjcul + * + * @param <V> The type of the value + * @param <A> The ignored argument type + */ public class Const<V, A> implements Container<V, Const<V, ?>>{ private V payload; @@ -9,6 +17,16 @@ public class Const<V, A> implements Container<V, Const<V, ?>>{ this.payload = payload; } + /** + * Create a constant container. + * + * @param <V> The value contained + * @param <A> The ignored argument type + * + * @param val The type of the value + * + * @return A constant container giving the contained value + */ public static <V, A> Const<V, A> of(V val) { return new Const<>(val); } diff --git a/src/main/java/bjc/functypes/Predicates.java b/src/main/java/bjc/functypes/Predicates.java index 3977294..7c670ea 100644 --- a/src/main/java/bjc/functypes/Predicates.java +++ b/src/main/java/bjc/functypes/Predicates.java @@ -18,9 +18,6 @@ */ package bjc.functypes; -import java.util.function.BiPredicate; -import java.util.function.Predicate; - /** * Various utility functions for predicates * @author bjcul diff --git a/src/main/java/bjc/functypes/ThrowFunction.java b/src/main/java/bjc/functypes/ThrowFunction.java index 5c61161..084b156 100644 --- a/src/main/java/bjc/functypes/ThrowFunction.java +++ b/src/main/java/bjc/functypes/ThrowFunction.java @@ -73,13 +73,13 @@ public interface ThrowFunction<InputType, ReturnType, ExType extends Throwable> if (clasz.isInstance(ex)) { // Swallow this return handler.apply((ExType) ex); - } else { - String msg = "Exception of incorrect type to be handled, only " - + clasz.getName() - + " are handled"; - - throw new RuntimeException(msg, ex); } + + String msg = "Exception of incorrect type to be handled, only " + + clasz.getName() + + " are handled"; + + throw new RuntimeException(msg, ex); } }; } @@ -122,13 +122,13 @@ public interface ThrowFunction<InputType, ReturnType, ExType extends Throwable> if (clasz.isInstance(ex)) { // Swallow this return self.apply(rescue.apply(arg, (ExType) ex)); - } else { - String msg = "Exception of incorrect type to be handled, only " - + clasz.getName() - + " are handled"; - - throw new RuntimeException(msg, ex); } + + String msg = "Exception of incorrect type to be handled, only " + + clasz.getName() + + " are handled"; + + throw new RuntimeException(msg, ex); } }); } diff --git a/src/main/java/bjc/functypes/TriFunction.java b/src/main/java/bjc/functypes/TriFunction.java index 988b311..4bb2a72 100644 --- a/src/main/java/bjc/functypes/TriFunction.java +++ b/src/main/java/bjc/functypes/TriFunction.java @@ -83,10 +83,24 @@ public interface TriFunction<In1, In2, In3, Out> { return (x, y) -> apply(x, y, z); } + /** + * Partially apply the second argument. + * + * @param y The value for the second argument + * + * @return The function w/ the second argument partially applied + */ public default BiFunction<In1, In3, Out> partialMiddle(In2 y) { return (x, z) -> apply(x, y, z); } + /** + * Partially apply the first argument. + * + * @param x The value for the first argument + * + * @return The function w/ the first argument partially applied + */ public default BiFunction<In2, In3, Out> partialFirst(In1 x) { return (y, z) -> apply(x, y, z); } diff --git a/src/main/java/bjc/functypes/VarArgFunction.java b/src/main/java/bjc/functypes/VarArgFunction.java new file mode 100644 index 0000000..a1c3814 --- /dev/null +++ b/src/main/java/bjc/functypes/VarArgFunction.java @@ -0,0 +1,22 @@ +package bjc.functypes; + +import java.util.List; + +/** + * Functional interface for a function that takes and returns an array of arguments + * @author bjcul + * + * @param <Input> The argument type + * @param <Output> The return type + */ +public interface VarArgFunction<Input, Output> { + /** + * Apply this function + * + * @param inputs The inputs to apply it to + * @return The results of applying it + */ + // It'd certainly be more convenient to have this return an array, but generics + // + arrays do not play well together + public List<Output> apply(@SuppressWarnings("unchecked") Input... inputs); +} diff --git a/src/main/java/bjc/optics/Adapter.java b/src/main/java/bjc/optics/Adapter.java new file mode 100644 index 0000000..8ad082f --- /dev/null +++ b/src/main/java/bjc/optics/Adapter.java @@ -0,0 +1,15 @@ +package bjc.optics; + +import bjc.typeclasses.BiContainer; + +/** + * A type-invariant adapter + * @author bjcul + * + * @param <From> The source type + * @param <To> The destination type + */ +public interface Adapter<From, To> + extends AdapterX<From, From, To, To>, BiContainer<From, To, Adapter<From, To>> { + // TODO: write 'of' function +} diff --git a/src/main/java/bjc/optics/AdapterX.java b/src/main/java/bjc/optics/AdapterX.java new file mode 100644 index 0000000..f037508 --- /dev/null +++ b/src/main/java/bjc/optics/AdapterX.java @@ -0,0 +1,89 @@ +/* + * esodata - data structures 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 <https://www.gnu.org/licenses/>. + */ +package bjc.optics; + +import java.util.function.Function; + +/** + * An adapter that maps between two sets of types + * + * @author bjcul + * + * @param <F1> The type of the first source + * @param <F2> The type of the second source + * @param <T1> The type of the first destination + * @param <T2> The type of the second destination + */ +public interface AdapterX<F1, F2, T1, T2> extends Optic<F1, F2, T1, T2> { + + /** + * Create a source from a destination + * + * @param source The destination to use + * + * @return A source corresponding to the destination + */ + F1 from(T1 source); + + /** + * Create a destination from a source + * + * @param source The source to use + * + * @return A destination corresponding to the source + */ + T2 to(F2 source); + + /** + * Create an adapter from its component parts + * + * @param <F1> The type of the first source + * @param <F2> The type of the second source + * @param <T1> The type of the first destination + * @param <T2> The type of the second destination + * + * @param f The 'from' function + * @param g The 'to' function + * + * @return The adapter constructed from the given parts. + */ + public static <F1, F2, T1, T2> AdapterX<F1, F2, T1, T2> of(Function<T1, F1> f, Function<F2, T2> g) { + return new FunctionalAdapterX<>(f, g); + } +} + +final class FunctionalAdapterX<W1, W2, P1, P2> implements AdapterX<W1, W2, P1, P2> { + private final Function<P1, W1> f; + private final Function<W2, P2> g; + + public FunctionalAdapterX(Function<P1, W1> f, Function<W2, P2> g) { + this.f = f; + this.g = g; + } + + @Override + public W1 from(P1 source) { + return f.apply(source); + } + + @Override + public P2 to(W2 source) { + return g.apply(source); + } +} diff --git a/src/main/java/bjc/optics/Adapters.java b/src/main/java/bjc/optics/Adapters.java new file mode 100644 index 0000000..13a9d02 --- /dev/null +++ b/src/main/java/bjc/optics/Adapters.java @@ -0,0 +1,47 @@ +/* + * esodata - data structures of varying use + * 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 <https://www.gnu.org/licenses/>. + */ +package bjc.optics; + +import bjc.data.Pair; +import bjc.data.Triple; + +/** + * Various utilities for dealing with adapters + * + * @author bjcul + * + */ +public class Adapters { + /** + * Create an adapter between triples and left-nested pairs. + * + * @param <A1> The first left type + * @param <A2> The second left type + * @param <B1> The first middle type + * @param <B2> The second middle type + * @param <C1> The first right type + * @param <C2> The second right type + * + * @return An adapter between triples and left-nested pairs + */ + public static <A1, A2, B1, B2, C1, C2> AdapterX<Triple<A1, B1, C1>, Triple<A2, B2, C2>, Pair<Pair<A1, B1>, C1>, + Pair<Pair<A2, B2>, C2>> flatten() { + return AdapterX.of((par) -> Triple.of(par.getLeft().getLeft(), par.getLeft().getRight(), par.getRight()), + (trp) -> Pair.pair(Pair.pair(trp.left(), trp.middle()), trp.right())); + } +} diff --git a/src/main/java/bjc/optics/Lens.java b/src/main/java/bjc/optics/Lens.java index be10eef..e8cab84 100644 --- a/src/main/java/bjc/optics/Lens.java +++ b/src/main/java/bjc/optics/Lens.java @@ -17,8 +17,9 @@ */ package bjc.optics; -import java.util.function.Function; -import java.util.function.UnaryOperator; +import static bjc.optics.Lenses.immutable; + +import java.util.function.*; import bjc.typeclasses.BiContainer; @@ -28,21 +29,22 @@ import bjc.typeclasses.BiContainer; * @author bjcul * * @param <Whole> The item this lens can focus on - * @param <Part> The field this lens focuses on + * @param <Part> The field this lens focuses on */ -public interface Lens<Whole, Part> extends LensX<Whole, Whole, Part, Part>, BiContainer<Whole, Part, Lens<Whole, Part>> { +public interface Lens<Whole, Part> + extends LensX<Whole, Whole, Part, Part>, BiContainer<Whole, Part, Lens<Whole, Part>> { /** * Modify a given whole using an operation * * @param source The whole to modify. - * @param mod The operation to use for modifying a part + * @param mod The operation to use for modifying a part * * @return A modified whole */ default Whole modify(Whole source, UnaryOperator<Part> mod) { return set(source, mod.apply(get(source))); } - + /** * Create a function which sets the part of a given whole. * @@ -53,16 +55,36 @@ public interface Lens<Whole, Part> extends LensX<Whole, Whole, Part, Part>, BiCo default Function<Whole, Whole> setting(Part part) { return (whole) -> set(whole, part); } - + /** * Lift a function that modifies parts to one that modifies wholes. * * @param f The function which operates on parts * - * @return A corresponding function which applies the given modification to a part. + * @return A corresponding function which applies the given modification to a + * part. */ default Function<Whole, Whole> lift(UnaryOperator<Part> f) { // modify will be more efficient for some lenses return (whole) -> modify(whole, f); } + + /** + * Compose two type-variant lenses together. + * + * @param <V1> The first type the second lens focuses on + * @param <V2> The second type the second lens focuses on. + * + * @param other The second lens to use. + * + * @return A lens composed from this one and the given one. + */ + default <V1> Lens<Whole, V1> compose(Lens<Part, V1> other) { + LensX<Whole, Whole, V1, V1> lensX = immutable((whole) -> other.get(get(whole)), + (whole, part) -> update(whole, (val2) -> other.set(val2, part))); + // Note: if lensX is inlined, then the setter function for the lens has to be + // externalized, otherwise type-inference goes BOOM and everything fails. + // Should ask on stack overflow why that is + return (Lens<Whole, V1>) lensX; + } } diff --git a/src/main/java/bjc/optics/LensX.java b/src/main/java/bjc/optics/LensX.java index d0f83be..02777e2 100644 --- a/src/main/java/bjc/optics/LensX.java +++ b/src/main/java/bjc/optics/LensX.java @@ -19,7 +19,6 @@ package bjc.optics; import static bjc.optics.Lenses.immutable; -import java.util.function.BiFunction; import java.util.function.Function; /** diff --git a/src/main/java/bjc/optics/Lenses.java b/src/main/java/bjc/optics/Lenses.java index 6cebc84..aad5571 100644 --- a/src/main/java/bjc/optics/Lenses.java +++ b/src/main/java/bjc/optics/Lenses.java @@ -76,7 +76,7 @@ public class Lenses { public static <Part1, Part2> LensX<Holder<Part1>, Holder<Part2>, Part1, Part2> holder() { return immutable((hld) -> hld.getValue(), (hld, val) -> hld.map((vl) -> val)); } - + /** * Create a lens for updating tagged pairs. * @@ -92,7 +92,13 @@ public class Lenses { public static <A, B, T> LensX<Pair<T, A>, Pair<T, B>, A, B> tagged() { return immutable((par) -> par.getRight(), (par, val) -> par.mapRight((vl) -> val)); } - + + // Not entirely sure what I was thinking when I wrote this. Pretty sure this + // would need W1 to be a monoid to make much sense + // public static <W1, P1, P2> Lens<W1, Pair<P1, P2>> both(Lens<W1, P1> lhs, + // Lens<W1, P2> rhs) { + // } + /** * Creates a lens which focuses on a piece of internal state. * @@ -107,7 +113,7 @@ public class Lenses { Holder<A> hold = Holder.of(val); return immutable((whole) -> hold.getValue(), (whole, vl) -> hold.map((arg) -> vl)); } - + /** * Creates a lens which focuses on a piece of mutable internal state. * @@ -121,6 +127,17 @@ public class Lenses { Holder<A> hold = Holder.of(val); return mutable((whole) -> hold.getValue(), (whole, vl) -> hold.replace(vl)); } + + /** + * Create a lens that focuses on the sign of an integer + * + * @return A lens that focuses on the sign of an integer + */ + public static Lens<Integer, Boolean> sign() { + LensX<Integer, Integer, Boolean, + Boolean> lensX = immutable((num) -> num >= 0, (num, sgn) -> sgn ? Math.abs(num) : -Math.abs(num)); + return (Lens<Integer, Boolean>) lensX; + } } final class FunctionalLensX<W1, W2, P1, P2> implements LensX<W1, W2, P1, P2> { diff --git a/src/main/java/bjc/optics/Prism.java b/src/main/java/bjc/optics/Prism.java new file mode 100644 index 0000000..a04939b --- /dev/null +++ b/src/main/java/bjc/optics/Prism.java @@ -0,0 +1,70 @@ +/* + * esodata - data structures 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 <https://www.gnu.org/licenses/>. + */ +package bjc.optics; + +import java.util.function.Function; + +import bjc.data.Either; +import bjc.typeclasses.BiContainer; + +/** + * A type-invariant prism + * + * @author bjcul + * + * @param <Whole> The type of the whole + * @param <Part> The type of the part + */ +public interface Prism<Whole, Part> + extends PrismX<Whole, Whole, Part, Part>, BiContainer<Whole, Part, Prism<Whole, Part>> { + + /** + * Create a type-invariant prism from its component parts. + * + * @param <Whole> The type of the whole + * @param <Part> The type of the part + * + * @param f The 'match' function of the prism + * @param g The 'build' function of the prism + * + * @return The prism composed of the given parts. + */ + static <Whole, Part> Prism<Whole, Part> of(Function<Part, Either<Part, Whole>> f, Function<Whole, Part> g) { + return new FunctionalPrism<>(g, f); + } +} + +final class FunctionalPrism<Whole, Part> implements Prism<Whole, Part> { + private final Function<Whole, Part> g; + private final Function<Part, Either<Part, Whole>> f; + + public FunctionalPrism(Function<Whole, Part> g, Function<Part, Either<Part, Whole>> f) { + this.g = g; + this.f = f; + } + + @Override + public Part build(Whole whole) { + return g.apply(whole); + } + + @Override + public Either<Part, Whole> match(Part part) { + return f.apply(part); + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/optics/PrismX.java b/src/main/java/bjc/optics/PrismX.java index b4986cf..0f4a0e0 100644 --- a/src/main/java/bjc/optics/PrismX.java +++ b/src/main/java/bjc/optics/PrismX.java @@ -17,6 +17,73 @@ */ package bjc.optics; +import java.util.function.Function; + +import bjc.data.Either; + +/** + * Represents a Prism, which is a type of optic. + * + * TODO: Add better description + * + * @author bjcul + * + * @param <W1> The type of the first whole + * @param <W2> The type of the second whole + * @param <P1> The type of the first part + * @param <P2> The type of the second part + */ public interface PrismX<W1, W2, P1, P2> extends Optic<W1, W2, P1, P2> { + /** + * Match against this prism. + * + * @param part The part to match + * @return Either the matched value or the prism + */ + Either<P2, W1> match(P1 part); + /** + * Build this prism from a given part. + * + * @param whole The whole to build from + * @return The part that is constructed + */ + P2 build(W2 whole); + + /** + * Create a prism from its component parts + * + * @param <W1> The type of the first whole + * @param <W2> The type of the second whole + * @param <P1> The type of the first part + * @param <P2> The type of the second part + * + * @param f The 'match' function for the prism + * @param g The 'build' function for the prism + * + * @return A prism built from the given parts + */ + static <W1, W2, P1, P2> PrismX<W1, W2, P1, P2> of(Function<P1, Either<P2, W1>> f, Function<W2, P2> g) { + return new FunctionalPrismX<>(g, f); + } } + +final class FunctionalPrismX<W1, W2, P1, P2> implements PrismX<W1, W2, P1, P2> { + private final Function<W2, P2> g; + private final Function<P1, Either<P2, W1>> f; + + public FunctionalPrismX(Function<W2, P2> g, Function<P1, Either<P2, W1>> f) { + this.g = g; + this.f = f; + } + + @Override + public P2 build(W2 whole) { + return g.apply(whole); + } + + @Override + public Either<P2, W1> match(P1 part) { + return f.apply(part); + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/optics/Prisms.java b/src/main/java/bjc/optics/Prisms.java new file mode 100644 index 0000000..ae4a4ee --- /dev/null +++ b/src/main/java/bjc/optics/Prisms.java @@ -0,0 +1,56 @@ +/* + * esodata - data structures 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 <https://www.gnu.org/licenses/>. + */ +package bjc.optics; + +import java.util.Optional; + +import bjc.data.Either; + +/** + * Various utilities for working with prisms + * + * @author bjcul + * + */ +public class Prisms { + /** + * Create a prism that reflects on the value in an optional + * + * @param <L> The type contained in the optional + * @param <R> An auxiliary type + * + * TODO: better notes for what R is for + * + * @return A prism that reflects on an optional + */ + public static <L, R> PrismX<L, R, Optional<L>, Optional<R>> optional() { + return PrismX.of((opt) -> opt.isPresent() ? Either.right(opt.get()) : Either.left(Optional.empty()), + Optional::ofNullable); + } + + /** + * Create a prism that reflects on whether a double corresponds to a given + * integer. + * + * @return A prism on the int view of a double. + */ + public static Prism<Integer, Double> whole() { + return Prism.of((vl) -> Math.rint(vl) == vl ? Either.right(vl.intValue()) : Either.left(vl), + Integer::doubleValue); + } +} diff --git a/src/main/java/bjc/optics/Traversal.java b/src/main/java/bjc/optics/Traversal.java new file mode 100644 index 0000000..a41f2b9 --- /dev/null +++ b/src/main/java/bjc/optics/Traversal.java @@ -0,0 +1,14 @@ +package bjc.optics; + +import bjc.typeclasses.BiContainer; + +/** + * A traversal + * @author bjcul + * + * @param <C> The container type + * @param <E> The element type + */ +public interface Traversal<C, E> extends TraversalX<C, C, E, E>, BiContainer<C, E, Traversal<C, E>> { + // TODO implement 'of' +} diff --git a/src/main/java/bjc/optics/TraversalX.java b/src/main/java/bjc/optics/TraversalX.java new file mode 100644 index 0000000..54c1a0b --- /dev/null +++ b/src/main/java/bjc/optics/TraversalX.java @@ -0,0 +1,54 @@ +/* + * esodata - data structures of varying use + * 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 <https://www.gnu.org/licenses/>. + */ +package bjc.optics; + +import java.util.Collection; + +/** + * Represents an optic allowing access to the elements of a given item + * + * @author bjcul + * + * @param <C1> The first collection type + * @param <C2> The second collection type + * @param <E1> The first element type + * @param <E2> The second element type + */ +public interface TraversalX<C1, C2, E1, E2> extends Optic<C1, C2, E1, E2> { + // Note: these should be fixed size collections of the same type, but that would + // be awkward to represent + /** + * Extract the contents of the collection + * + * @param whole The collection to get the contents of. + * @return The contents of the given collection. + */ + Collection<E1> contents(C1 whole); + + /** + * Replace the contents of the given collection + * + * @param whole The collection to replace the contents of + * @param bits The new contents of the collection + * + * @return A collection with the new contents + */ + C2 fill(C1 whole, Collection<E2> bits); + + // TODO implement 'of' +} diff --git a/src/main/java/bjc/typeclasses/Applicative.java b/src/main/java/bjc/typeclasses/Applicative.java new file mode 100644 index 0000000..7e70c61 --- /dev/null +++ b/src/main/java/bjc/typeclasses/Applicative.java @@ -0,0 +1,39 @@ +package bjc.typeclasses; + +import java.util.function.Function; + +/** + * Represents an applicative + * @author bjcul + * + * @param <A> The contained type + * @param <App> The self type + */ +public interface Applicative<A, App extends Applicative<?, App>> extends FunctorX<A, App> { + /** + * Create an applicative from a value + * + * @param <B> The type of the value + * + * @param val The value + * + * @return An applicative containing the given value + */ + <B> Applicative<B, App> pure(B val); + + /** + * Apply the given applicative + * + * @param <B> The type of the result + * + * @param func An applicative containing a function + * + * @return An applicative containing the result of applying the function + */ + <B> Applicative<B, App> app(Applicative<Function<? super A, ? extends B>, App> func); + + @Override + default <B> FunctorX<B, App> fmap(Function<? super A, ? extends B> fn) { + return app(pure(fn)); + } +} diff --git a/src/main/java/bjc/typeclasses/BiContainer.java b/src/main/java/bjc/typeclasses/BiContainer.java index 9be00ca..4be0200 100644 --- a/src/main/java/bjc/typeclasses/BiContainer.java +++ b/src/main/java/bjc/typeclasses/BiContainer.java @@ -17,6 +17,14 @@ */ package bjc.typeclasses; +/** + * Marker interface for BiContainers + * @author bjcul + * + * @param <L> The left value type + * @param <R> The right value type + * @param <C> The self type + */ public interface BiContainer<L, R, C extends BiContainer<?, ?, C>> { // marker } diff --git a/src/main/java/bjc/typeclasses/Container.java b/src/main/java/bjc/typeclasses/Container.java index b1e3e34..76bad31 100644 --- a/src/main/java/bjc/typeclasses/Container.java +++ b/src/main/java/bjc/typeclasses/Container.java @@ -17,6 +17,13 @@ */ package bjc.typeclasses; +/** + * Marker type for containers + * @author bjcul + * + * @param <T> The value type + * @param <C> The self type + */ public interface Container<T, C extends Container<?, C>> { // Marker } diff --git a/src/main/java/bjc/typeclasses/FunList.java b/src/main/java/bjc/typeclasses/FunList.java index cd16c82..78717af 100644 --- a/src/main/java/bjc/typeclasses/FunList.java +++ b/src/main/java/bjc/typeclasses/FunList.java @@ -4,10 +4,30 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Function; +/** + * Represent a FunList data structure which contains a B and zero or more As + * @author bjcul + * + * @param <A> The type for A + * @param <B> The type for B + */ public sealed interface FunList<A, B> permits FunList.Done<A, B>, FunList.More<A, B> { + /** + * Represents a FunList that contains a B and zero As + * + * @author bjcul + * + * @param <A> Unused type + * @param <B> Type of the contained value + */ public final class Done<A, B> implements FunList<A, B> { private final B val; + /** + * Create a new Done FunList + * + * @param val The contained value + */ public Done(B val) { this.val = val; } @@ -23,10 +43,23 @@ public sealed interface FunList<A, B> permits FunList.Done<A, B>, FunList.More<A } } + /** + * A FunList that contains an A and another FunList + * @author bjcul + * + * @param <A> The contained type + * @param <B> The type of the eventual result + */ public final class More<A, B> implements FunList<A, B> { private A val; private FunList<A, Function<A, B>> rest; + /** + * Create a FunList + * + * @param val The contained value + * @param rest The rest of the list + */ public More(A val, FunList<A, Function<A, B>> rest) { this.val = val; this.rest = rest; @@ -47,9 +80,23 @@ public sealed interface FunList<A, B> permits FunList.Done<A, B>, FunList.More<A } } + /** + * Get the eventual result + * @return the eventual result + */ public B getB(); + /** + * Get the contained arguments + * + * @return The arguments + */ public List<A> getAs(); // https://twanvl.nl/blog/haskell/non-regular1 + + // Notes have the following signatures instead + // Done<T> extends Holder<T> + // More<A, B> extends Pair<A, B> + // FunList<A, B, T> extends Either<Done<T>, More<A, FunList<A, B, Function<B, T>>>> } diff --git a/src/main/java/bjc/typeclasses/FunctorX.java b/src/main/java/bjc/typeclasses/FunctorX.java new file mode 100644 index 0000000..137cc3f --- /dev/null +++ b/src/main/java/bjc/typeclasses/FunctorX.java @@ -0,0 +1,10 @@ +package bjc.typeclasses; + +import java.util.function.Function; + +// TODO: determine if it makes sense to replace regular Functor w/ this +public interface FunctorX<A, F extends FunctorX<?, F>> extends Container<A, F> { + <B> FunctorX<B, F> fmap(Function<? super A, ? extends B> fn); + + // Actually no way to write a 'of' function here; the embedded B gets in our way +} diff --git a/src/main/java/bjc/typeclasses/ListC.java b/src/main/java/bjc/typeclasses/ListC.java index 16dca8a..be3d24c 100644 --- a/src/main/java/bjc/typeclasses/ListC.java +++ b/src/main/java/bjc/typeclasses/ListC.java @@ -19,13 +19,29 @@ package bjc.typeclasses; import java.util.List; +/** + * A list wrapped in a container + * @author bjcul + * + * @param <T> The type contained + */ public class ListC<T> implements Container<T, ListC<?>> { private List<T> contained; + /** + * Create a new contained list + * + * @param contained The contained list + */ public ListC(List<T> contained) { this.contained = contained; } + /** + * Retrieve the contained list + * + * @return The contained list + */ public List<T> list() { return contained; } diff --git a/src/main/java/bjc/typeclasses/PFLens.java b/src/main/java/bjc/typeclasses/PFLens.java index 0468efb..3574cde 100644 --- a/src/main/java/bjc/typeclasses/PFLens.java +++ b/src/main/java/bjc/typeclasses/PFLens.java @@ -7,12 +7,23 @@ import java.util.function.Function; * * @author bjcul * - * @param <Whole1> - * @param <Whole2> - * @param <Part1> - * @param <Part2> + * @param <Whole1> The first whole + * @param <Whole2> The second whole + * @param <Part1> The first part + * @param <Part2> The second part */ public interface PFLens<Whole1, Whole2, Part1, Part2> { - // Container should be Functor once gthat is ironed out + // Container should be Functor once that is ironed out + /** + * Run the lens in the given functor + * + * @param <A> First argument + * @param <B> second argument + * @param <F> Underlying functor + * + * @param f The function to apply + * + * @return The result of applying the functor + */ <A, B, F extends Container<?, F>> Function<Whole1, Container<Whole2, F>> run(Function<Part1, Container<Part2, F>> f); } diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index edae185..13e211b 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -28,4 +28,6 @@ module esodata { exports bjc.funcdata.bst; exports bjc.funcdata.theory; exports bjc.funcdata; + exports bjc.typeclasses; + exports bjc.optics; }
\ No newline at end of file |
