summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/bjc/data/BooleanToggle.java2
-rw-r--r--src/main/java/bjc/data/Either.java24
-rw-r--r--src/main/java/bjc/data/Lazy.java17
-rw-r--r--src/main/java/bjc/data/OneWayToggle.java3
-rw-r--r--src/main/java/bjc/data/Pair.java9
-rw-r--r--src/main/java/bjc/data/PetriNet.java17
-rw-r--r--src/main/java/bjc/data/PetriTransition.java59
-rw-r--r--src/main/java/bjc/data/Triple.java78
-rw-r--r--src/main/java/bjc/data/ValueToggle.java6
-rw-r--r--src/main/java/bjc/esodata/AbbrevMap2.java71
-rw-r--r--src/main/java/bjc/esodata/ClosedSpoolException.java48
-rw-r--r--src/main/java/bjc/esodata/ComplexSpooler.java43
-rw-r--r--src/main/java/bjc/esodata/DefaultList.java3
-rw-r--r--src/main/java/bjc/esodata/DefaultSpool.java80
-rw-r--r--src/main/java/bjc/esodata/DefaultSpooler.java43
-rw-r--r--src/main/java/bjc/esodata/KeyedList.java11
-rw-r--r--src/main/java/bjc/esodata/Multimap.java5
-rw-r--r--src/main/java/bjc/esodata/NestList.java6
-rw-r--r--src/main/java/bjc/esodata/PushdownMap.java4
-rw-r--r--src/main/java/bjc/esodata/Spool.java48
-rw-r--r--src/main/java/bjc/esodata/Spooler.java42
-rw-r--r--src/main/java/bjc/esodata/TSetMultimap.java3
-rw-r--r--src/main/java/bjc/esodata/TapeLibrary.java4
-rw-r--r--src/main/java/bjc/esodata/spool/Spool.java22
-rw-r--r--src/main/java/bjc/esodata/spool/Spooler.java22
-rw-r--r--src/main/java/bjc/funcdata/ExtendedMap.java13
-rw-r--r--src/main/java/bjc/funcdata/Freezable.java1
-rw-r--r--src/main/java/bjc/funcdata/FunctionalMap.java8
-rw-r--r--src/main/java/bjc/funcdata/MapEx.java2
-rw-r--r--src/main/java/bjc/funcdata/TransformedValueMap.java4
-rw-r--r--src/main/java/bjc/functypes/Combinators.java17
-rw-r--r--src/main/java/bjc/functypes/Const.java18
-rw-r--r--src/main/java/bjc/functypes/Predicates.java3
-rw-r--r--src/main/java/bjc/functypes/ThrowFunction.java24
-rw-r--r--src/main/java/bjc/functypes/TriFunction.java14
-rw-r--r--src/main/java/bjc/functypes/VarArgFunction.java22
-rw-r--r--src/main/java/bjc/optics/Adapter.java15
-rw-r--r--src/main/java/bjc/optics/AdapterX.java89
-rw-r--r--src/main/java/bjc/optics/Adapters.java47
-rw-r--r--src/main/java/bjc/optics/Lens.java38
-rw-r--r--src/main/java/bjc/optics/LensX.java1
-rw-r--r--src/main/java/bjc/optics/Lenses.java23
-rw-r--r--src/main/java/bjc/optics/Prism.java70
-rw-r--r--src/main/java/bjc/optics/PrismX.java67
-rw-r--r--src/main/java/bjc/optics/Prisms.java56
-rw-r--r--src/main/java/bjc/optics/Traversal.java14
-rw-r--r--src/main/java/bjc/optics/TraversalX.java54
-rw-r--r--src/main/java/bjc/typeclasses/Applicative.java39
-rw-r--r--src/main/java/bjc/typeclasses/BiContainer.java8
-rw-r--r--src/main/java/bjc/typeclasses/Container.java7
-rw-r--r--src/main/java/bjc/typeclasses/FunList.java47
-rw-r--r--src/main/java/bjc/typeclasses/FunctorX.java10
-rw-r--r--src/main/java/bjc/typeclasses/ListC.java16
-rw-r--r--src/main/java/bjc/typeclasses/PFLens.java21
-rw-r--r--src/main/java/module-info.java2
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