diff --git a/README.md b/README.md
index 076a31dad..2dd80178d 100644
--- a/README.md
+++ b/README.md
@@ -32,14 +32,14 @@ Add the following dependency to your:
com.jnape.palatablelambda
- 1.1
+ 1.2
```
`build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)):
```gradle
- compile group: 'com.jnape.palatable', name: 'lambda', version: '1.1'
+ compile group: 'com.jnape.palatable', name: 'lambda', version: '1.2'
```
@@ -57,7 +57,7 @@ First, the obligatory `map`/`filter`/`reduce` example:
Every function in lambda is [curried](https://www.wikiwand.com/en/Currying), so we could have also done this:
```Java
- MonadicFunction, Integer> sumOfEvenIncrementsFn =
+ Fn1, Integer> sumOfEvenIncrementsFn =
map((Integer x) -> x + 1)
.then(filter(x -> x % 2 == 0))
.then(reduceLeft((x, y) -> x + y));
@@ -95,20 +95,20 @@ What if we want the cross product of a domain and codomain:
Let's compose two functions:
```Java
- MonadicFunction add = x -> x + 1;
- MonadicFunction subtract = x -> x -1;
+ Fn1 add = x -> x + 1;
+ Fn1 subtract = x -> x -1;
- MonadicFunction noOp = add.then(subtract);
+ Fn1 noOp = add.then(subtract);
// same as
- MonadicFunction alsoNoOp = subtract.fmap(add);
+ Fn1 alsoNoOp = subtract.fmap(add);
```
And partially apply some:
```Java
- DyadicFunction add = (x, y) -> x + y;
+ Fn2 add = (x, y) -> x + y;
- MonadicFunction add1 = add.apply(1);
+ Fn1 add1 = add.apply(1);
add1.apply(2);
//-> 3
```
@@ -152,7 +152,7 @@ To address this, tuples in lambda are specializations of `HList`s up to 5 elemen
```Java
HNil nil = HList.nil();
- Singleton singleton = nil.cons(5);
+ SingletonHList singleton = nil.cons(5);
Tuple2 tuple2 = singleton.cons(4);
Tuple3 tuple3 = tuple2.cons(3);
Tuple4 tuple4 = tuple3.cons(2);
@@ -165,7 +165,7 @@ To address this, tuples in lambda are specializations of `HList`s up to 5 elemen
Additionally, `HList` provides convenience static factory methods for directly constructing lists of up to 5 elements:
```Java
- Singleton singleton = HList.singleton(1);
+ SingletonHList singleton = HList.singletonHList(1);
Tuple2 tuple2 = HList.tuple(1, 2);
Tuple3 tuple3 = HList.tuple(1, 2, 3);
Tuple4 tuple4 = HList.tuple(1, 2, 3, 4);
@@ -187,6 +187,21 @@ Finally, all `Tuple*` classes are instances of both `Functor` and `Bifunctor`:
System.out.println(mappedTuple3._3()); // prints 2
```
+### Heterogeneous Maps
+
+HMaps are type-safe heterogeneous maps, meaning they can store mappings to different value types in the same map; however, whereas HLists encode value types in their type signatures, HMaps rely on the keys to encode the value type that they point to.
+
+```Java
+ TypeSafeKey stringKey = TypeSafeKey.typeSafeKey();
+ TypeSafeKey intKey = TypeSafeKey.typeSafeKey();
+ HMap hmap = HMap.hMap(stringKey, "string value",
+ intKey, 1);
+
+ Optional stringValue = hmap.get(stringKey); // Optional["string value"]
+ Optional intValue = hmap.get(intKey); // Optional[1]
+ Optional anotherIntValue = hmap.get(anotherIntKey); // Optional.empty
+```
+
### Either
Binary tagged unions are represented as `Either`s, which resolve to one of two possible values: a `Left` value wrapping an `L`, or a `Right` value wrapping an `R` (typically an exceptional value or a successful value, respectively).
diff --git a/pom.xml b/pom.xml
index 30e571f91..215859eae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
lambda
- 1.2
+ 1.3jarLambda
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Either.java b/src/main/java/com/jnape/palatable/lambda/adt/Either.java
index b286f7d54..371e5d355 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java
@@ -1,7 +1,7 @@
package com.jnape.palatable.lambda.adt;
-import com.jnape.palatable.lambda.functions.DyadicFunction;
-import com.jnape.palatable.lambda.functions.MonadicFunction;
+import com.jnape.palatable.lambda.functions.Fn1;
+import com.jnape.palatable.lambda.functions.Fn2;
import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier;
import com.jnape.palatable.lambda.functor.Bifunctor;
import com.jnape.palatable.lambda.functor.Functor;
@@ -11,7 +11,7 @@
import java.util.function.Consumer;
import java.util.function.Supplier;
-import static com.jnape.palatable.lambda.functions.builtin.monadic.Identity.id;
+import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
/**
* The binary tagged union. General semantics tend to connote "success" values via the right value and "failure" values
@@ -26,52 +26,136 @@ public abstract class Either implements Functor, Bifunctor {
private Either() {
}
+ /**
+ * Return the value wrapped by this Either if it's a right value; otherwise, return defaultValue.
+ *
+ * @param defaultValue the value to return if this is a left
+ * @return the value wrapped by this Either if right; otherwise, defaultValue
+ */
public final R or(R defaultValue) {
return recover(l -> defaultValue);
}
- public final R recover(MonadicFunction super L, ? extends R> recoveryFn) {
+ /**
+ * "Recover" from a left value by applying a recoveryFn to the wrapped value and returning it in the case of a left
+ * value; otherwise, return the wrapped right value.
+ *
+ * @param recoveryFn a function from L to R
+ * @return either the wrapped value (if right) or the result of the left value applied to recoveryFn
+ */
+ public final R recover(Fn1 super L, ? extends R> recoveryFn) {
return match(recoveryFn, id());
}
- public final L forfeit(MonadicFunction super R, ? extends L> forfeitFn) {
+ /**
+ * Inverse of recover. If this is a right value, apply the wrapped value to forfeitFn and return it; otherwise,
+ * return the wrapped left value;
+ *
+ * @param forfeitFn a function from R to L
+ * @return either the wrapped value (if left) or the result of the right value applied to forfeitFn
+ */
+ public final L forfeit(Fn1 super R, ? extends L> forfeitFn) {
return match(id(), forfeitFn);
}
- public final R orThrow(
- MonadicFunction super L, ? extends E> throwableFn) throws E {
+ /**
+ * Return the wrapped value if this is a right; otherwise, map the wrapped left value to an E and throw
+ * it.
+ *
+ * @param throwableFn a function from L to E
+ * @param the left parameter type (the throwable exception type)
+ * @return the wrapped value if this is a right
+ * @throws E the result of applying the wrapped left value to throwableFn, if this is a left
+ */
+ public final R orThrow(Fn1 super L, ? extends E> throwableFn) throws E {
return match(l -> {
throw throwableFn.apply(l);
}, id());
}
- public final Either filter(MonadicFunction super R, Boolean> pred,
- Supplier leftSupplier) {
+ /**
+ * If this is a right value, apply pred to it. If the result is true, return the same value; otherwise, return the
+ * result of leftSupplier wrapped as a left value.
+ *
+ * If this is a left value, return it.
+ *
+ * @param pred the predicate to apply to a right value
+ * @param leftSupplier the supplier of a left value if pred fails
+ * @return this if a left value or a right value that pred matches; otherwise, the result of leftSupplier wrapped in
+ * a left
+ */
+ public final Either filter(Fn1 super R, Boolean> pred, Supplier leftSupplier) {
return flatMap(r -> pred.apply(r) ? right(r) : left(leftSupplier.get()));
}
- public final Either flatMap(MonadicFunction super R, ? extends Either> rightFn) {
+ /**
+ * If a right value, unwrap it and apply it to rightFn, returning the resulting
+ * Either<L ,R>. Otherwise, return the left value.
+ *
+ * Note that because this monadic form of flatMap only supports mapping over a theoretical right value,
+ * the resulting Either must be invariant on the same left value to flatten properly.
+ *
+ * @param rightFn the function to apply to a right value
+ * @param the new right parameter type
+ * @return the Either resulting from applying rightFn to this right value, or this left value if left
+ */
+ public final Either flatMap(Fn1 super R, ? extends Either> rightFn) {
return flatMap(Either::left, rightFn);
}
- public final Either flatMap(MonadicFunction super L, ? extends Either> leftFn,
- MonadicFunction super R, ? extends Either> rightFn) {
+ /**
+ * If a right value, apply rightFn to the unwrapped right value and return the resulting
+ * Either; otherwise, apply the unwrapped left value to leftFn and return the resulting
+ * Either.
+ *
+ * @param leftFn the function to apply if a left value
+ * @param rightFn the function to apply if a right value
+ * @param the new left parameter type
+ * @param the new right parameter type
+ * @return the result of either rightFn or leftFn, depending on whether this is a right or a left
+ */
+ public final Either flatMap(Fn1 super L, ? extends Either> leftFn,
+ Fn1 super R, ? extends Either> rightFn) {
return match(leftFn, rightFn);
}
- public final Either merge(DyadicFunction super L, ? super L, ? extends L> leftFn,
- DyadicFunction super R, ? super R, ? extends R> rightFn,
+ /**
+ * Given two binary operators over L and R, merge two Either<L, R>s into a single
+ * Either<L, R>. Note that merge biases towards left values; that is, if any left
+ * value exists, the result will be a left value, such that only unanimous right values result in an ultimate right
+ * value.
+ *
+ * @param leftFn the binary operator for L
+ * @param rightFn the binary operator for R
+ * @param other the other Either
+ * @return the merged Either
+ */
+ public final Either merge(Fn2 super L, ? super L, ? extends L> leftFn,
+ Fn2 super R, ? super R, ? extends R> rightFn,
Either other) {
return this.match(
l1 -> other.match(l2 -> left(leftFn.apply(l1, l2)), r -> left(l1)),
r1 -> other.match(Either::left, r2 -> right(rightFn.apply(r1, r2))));
}
+ /**
+ * Perform side-effects against a wrapped right value, returning back the Either unaltered.
+ *
+ * @param rightConsumer the effecting consumer
+ * @return the Either, unaltered
+ */
public Either peek(Consumer rightConsumer) {
return peek(l -> {
}, rightConsumer);
}
+ /**
+ * Perform side-effects against a wrapped right or left value, returning back the Either unaltered.
+ *
+ * @param leftConsumer the effecting consumer for left values
+ * @param rightConsumer the effecting consumer for right values
+ * @return the Either, unaltered
+ */
public Either peek(Consumer leftConsumer, Consumer rightConsumer) {
return flatMap(l -> {
leftConsumer.accept(l);
@@ -82,40 +166,70 @@ public Either peek(Consumer leftConsumer, Consumer rightConsumer) {
});
}
- public abstract V match(MonadicFunction super L, ? extends V> leftFn,
- MonadicFunction super R, ? extends V> rightFn);
+ /**
+ * Given two mapping functions (one from an L to a V, one from an R to a
+ * V), unwrap the value stored in this Either, apply the appropriate mapping function,
+ * and return the result.
+ *
+ * @param leftFn the left value mapping function
+ * @param rightFn the right value mapping function
+ * @param the result type
+ * @return the result of applying the appropriate mapping function to the wrapped value
+ */
+ public abstract V match(Fn1 super L, ? extends V> leftFn, Fn1 super R, ? extends V> rightFn);
@Override
- public final Either fmap(MonadicFunction super R, ? extends R2> fn) {
+ public final Either fmap(Fn1 super R, ? extends R2> fn) {
return biMapR(fn);
}
@Override
@SuppressWarnings("unchecked")
- public final Either biMapL(MonadicFunction super L, ? extends L2> fn) {
+ public final Either biMapL(Fn1 super L, ? extends L2> fn) {
return (Either) Bifunctor.super.biMapL(fn);
}
@Override
@SuppressWarnings("unchecked")
- public final Either biMapR(MonadicFunction super R, ? extends R2> fn) {
+ public final Either biMapR(Fn1 super R, ? extends R2> fn) {
return (Either) Bifunctor.super.biMapR(fn);
}
@Override
- public final Either biMap(MonadicFunction super L, ? extends L2> leftFn,
- MonadicFunction super R, ? extends R2> rightFn) {
+ public final Either biMap(Fn1 super L, ? extends L2> leftFn,
+ Fn1 super R, ? extends R2> rightFn) {
return match(l -> left(leftFn.apply(l)), r -> right(rightFn.apply(r)));
}
+ /**
+ * Convert an {@link Optional}<R> into an Either<L, R>, supplying the left value from
+ * leftFn in the case of {@link Optional#empty()}.
+ *
+ * @param optional the optional
+ * @param leftFn the supplier to use for left values
+ * @param the left parameter type
+ * @param the right parameter type
+ * @return a right value of the contained optional value, or a left value of leftFn's result
+ */
public static Either fromOptional(Optional optional, Supplier leftFn) {
return optional.>map(Either::right)
.orElse(left(leftFn.get()));
}
+ /**
+ * Attempt to execute the {@link CheckedSupplier}, returning its result in a right value. If the supplier throws an
+ * exception, apply leftFn to it, wrap it in a left value and return it.
+ *
+ * @param supplier the supplier of the right value
+ * @param leftFn a function mapping E to L
+ * @param the most contravariant exception that the supplier might throw
+ * @param the left parameter type
+ * @param the right parameter type
+ * @return the supplier result as a right value, or leftFn's mapping result as a left value
+ */
@SuppressWarnings("unchecked")
public static Either trying(CheckedSupplier supplier,
- MonadicFunction super E, ? extends L> leftFn) {
+ Fn1 super E, ? extends L> leftFn) {
try {
return right(supplier.get());
} catch (Exception e) {
@@ -123,14 +237,39 @@ public static Either trying(CheckedSupplier the left parameter type (the most contravariant exception that supplier might throw)
+ * @param the right parameter type
+ * @return the supplier result as a right value, or a left value of the thrown exception
+ */
public static Either trying(CheckedSupplier supplier) {
return trying(supplier, id());
}
+ /**
+ * Static factory method for creating a left value.
+ *
+ * @param l the wrapped value
+ * @param the left parameter type
+ * @param the right parameter type
+ * @return a left value of l
+ */
public static Either left(L l) {
return new Left<>(l);
}
+ /**
+ * Static factory method for creating a right value.
+ *
+ * @param r the wrapped value
+ * @param the left parameter type
+ * @param the right parameter type
+ * @return a right value of r
+ */
public static Either right(R r) {
return new Right<>(r);
}
@@ -143,8 +282,7 @@ private Left(L l) {
}
@Override
- public V match(MonadicFunction super L, ? extends V> leftFn,
- MonadicFunction super R, ? extends V> rightFn) {
+ public V match(Fn1 super L, ? extends V> leftFn, Fn1 super R, ? extends V> rightFn) {
return leftFn.apply(l);
}
@@ -174,8 +312,7 @@ private Right(R r) {
}
@Override
- public V match(MonadicFunction super L, ? extends V> leftFn,
- MonadicFunction super R, ? extends V> rightFn) {
+ public V match(Fn1 super L, ? extends V> leftFn, Fn1 super R, ? extends V> rightFn) {
return rightFn.apply(r);
}
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/HList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/HList.java
index feee8be92..aaebee9c7 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/HList.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/HList.java
@@ -3,12 +3,13 @@
import java.util.Objects;
/**
- * A heterogeneous list supporting arbitrary depth type-safety via a linearly recursive type signature. Note that due to
- * its rapidly expanding type signature, specializations exist up to certain depths to minimize typing overhead.
+ * An immutable heterogeneous list supporting arbitrary depth type-safety via a linearly recursive type signature. Note
+ * that due to its rapidly expanding type signature, specializations exist up to certain depths to minimize typing
+ * overhead.
*
* @param The head element type
* @param The encoded recursive tail HList type
- * @see Singleton
+ * @see SingletonHList
* @see Tuple2
* @see Tuple3
* @see Tuple4
@@ -19,32 +20,116 @@ public abstract class HList> {
private HList() {
}
+ /**
+ * Cons an element onto the front of this HList.
+ *
+ * @param newHead the new head element
+ * @param the new head type
+ * @return the updated HList
+ */
public abstract HCons> cons(NewHead newHead);
+ /**
+ * Static factory method for creating empty HLists.
+ *
+ * @return an empty HList
+ */
public static HNil nil() {
return HNil.INSTANCE;
}
+ /**
+ * Static factory method for creating an HList from the given head and tail.
+ *
+ * @param head the head element
+ * @param tail the tail HList
+ * @param the head type
+ * @param the tail type
+ * @return the newly created HList
+ */
public static > HCons cons(Head head, Tail tail) {
return new HCons<>(head, tail);
}
- public static Singleton singleton(Head head) {
- return new Singleton<>(head);
+ /**
+ * Static factory method for creating a singleton HList.
+ *
+ * @param head the head element
+ * @param the head element type
+ * @return the singleton HList
+ */
+ public static SingletonHList singletonHList(Head head) {
+ return new SingletonHList<>(head);
}
+ /**
+ * Static factory method for creating a 2-element HList.
+ *
+ * @param _1 the head element
+ * @param _2 the second element
+ * @param <_1> the head element type
+ * @param <_2> the second element type
+ * @return the 2-element HList
+ * @see Tuple2
+ */
+ @SuppressWarnings("JavaDoc")
public static <_1, _2> Tuple2<_1, _2> tuple(_1 _1, _2 _2) {
- return singleton(_2).cons(_1);
+ return singletonHList(_2).cons(_1);
}
+ /**
+ * Static factory method for creating a 3-element HList.
+ *
+ * @param _1 the head element
+ * @param _2 the second element
+ * @param _3 the third element
+ * @param <_1> the head element type
+ * @param <_2> the second element type
+ * @param <_3> the third element type
+ * @return the 3-element HList
+ * @see Tuple3
+ */
+ @SuppressWarnings("JavaDoc")
public static <_1, _2, _3> Tuple3<_1, _2, _3> tuple(_1 _1, _2 _2, _3 _3) {
return tuple(_2, _3).cons(_1);
}
+ /**
+ * Static factory method for creating a 4-element HList.
+ *
+ * @param _1 the head element
+ * @param _2 the second element
+ * @param _3 the third element
+ * @param _4 the fourth element
+ * @param <_1> the head element type
+ * @param <_2> the second element type
+ * @param <_3> the third element type
+ * @param <_4> the fourth element type
+ * @return the 4-element HList
+ * @see Tuple4
+ */
+ @SuppressWarnings("JavaDoc")
public static <_1, _2, _3, _4> Tuple4<_1, _2, _3, _4> tuple(_1 _1, _2 _2, _3 _3, _4 _4) {
return tuple(_2, _3, _4).cons(_1);
}
+ /**
+ * Static factory method for creating a 5-element HList.
+ *
+ * @param _1 the head element
+ * @param _2 the second element
+ * @param _3 the third element
+ * @param _4 the fourth element
+ * @param _5 the fifth element
+ * @param <_1> the head element type
+ * @param <_2> the second element type
+ * @param <_3> the third element type
+ * @param <_4> the fourth element type
+ * @param <_5> the fifth element type
+ * @return the 5-element HList
+ * @see Tuple5
+ */
+ @SuppressWarnings("JavaDoc")
public static <_1, _2, _3, _4, _5> Tuple5<_1, _2, _3, _4, _5> tuple(_1 _1, _2 _2, _3 _3, _4 _4, _5 _5) {
return tuple(_2, _3, _4, _5).cons(_1);
}
@@ -75,9 +160,8 @@ public Tail tail() {
public final boolean equals(Object other) {
if (other instanceof HCons) {
HCons that = (HCons) other;
- boolean sameHead = this.head.equals(that.head);
- boolean sameTail = this.tail.equals(that.tail);
- return sameHead && sameTail;
+ return this.head.equals(that.head)
+ && this.tail.equals(that.tail);
}
return false;
}
@@ -99,9 +183,12 @@ public final String toString() {
public static final class HNil extends HList {
private static final HNil INSTANCE = new HNil();
+ private HNil() {
+ }
+
@Override
- public Singleton cons(Head head) {
- return new Singleton<>(head);
+ public SingletonHList cons(Head head) {
+ return new SingletonHList<>(head);
}
@Override
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Singleton.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java
similarity index 55%
rename from src/main/java/com/jnape/palatable/lambda/adt/hlist/Singleton.java
rename to src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java
index fc6e66ee5..f651328a8 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Singleton.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java
@@ -2,11 +2,13 @@
import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
import com.jnape.palatable.lambda.adt.hlist.HList.HNil;
-import com.jnape.palatable.lambda.functions.MonadicFunction;
+import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functor.Functor;
+import java.util.RandomAccess;
+
/**
- * A singleton HList.
+ * A singleton HList. Supports random access.
*
* @param <_1> The single slot element type
* @see HList
@@ -15,9 +17,9 @@
* @see Tuple4
* @see Tuple5
*/
-public final class Singleton<_1> extends HCons<_1, HNil> implements Functor<_1> {
+public class SingletonHList<_1> extends HCons<_1, HNil> implements Functor<_1>, RandomAccess {
- Singleton(_1 _1) {
+ SingletonHList(_1 _1) {
super(_1, nil());
}
@@ -27,7 +29,7 @@ public <_0> Tuple2<_0, _1> cons(_0 _0) {
}
@Override
- public <_1Prime> Singleton<_1Prime> fmap(MonadicFunction super _1, ? extends _1Prime> fn) {
- return new Singleton<>(fn.apply(head()));
+ public <_1Prime> SingletonHList<_1Prime> fmap(Fn1 super _1, ? extends _1Prime> fn) {
+ return new SingletonHList<>(fn.apply(head()));
}
}
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple2.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple2.java
index 35001f291..222fb1f23 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple2.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple2.java
@@ -1,27 +1,32 @@
package com.jnape.palatable.lambda.adt.hlist;
import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
-import com.jnape.palatable.lambda.functions.MonadicFunction;
+import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functor.Bifunctor;
import com.jnape.palatable.lambda.functor.Functor;
import java.util.Map;
/**
- * A 2-element tuple product type, implemented as a specialized HList.
+ * A 2-element tuple product type, implemented as a specialized HList. Supports random access.
*
* @param <_1> The first slot element type
* @param <_2> The second slot element type
* @see HList
- * @see Singleton
+ * @see SingletonHList
* @see Tuple3
* @see Tuple4
* @see Tuple5
*/
-public final class Tuple2<_1, _2> extends HCons<_1, Singleton<_2>> implements Map.Entry<_1, _2>, Functor<_2>, Bifunctor<_1, _2> {
+public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements Map.Entry<_1, _2>, Functor<_2>, Bifunctor<_1, _2> {
- Tuple2(_1 _1, Singleton<_2> tail) {
+ private final _1 _1;
+ private final _2 _2;
+
+ Tuple2(_1 _1, SingletonHList<_2> tail) {
super(_1, tail);
+ this._1 = _1;
+ _2 = tail.head();
}
@Override
@@ -29,12 +34,22 @@ public <_0> Tuple3<_0, _1, _2> cons(_0 _0) {
return new Tuple3<>(_0, this);
}
+ /**
+ * Retrieve the first (head) element in constant time.
+ *
+ * @return the head element
+ */
public _1 _1() {
- return head();
+ return _1;
}
+ /**
+ * Retrieve the second element in constant time.
+ *
+ * @return the second element
+ */
public _2 _2() {
- return tail().head();
+ return _2;
}
@Override
@@ -53,29 +68,37 @@ public _2 setValue(_2 value) {
}
@Override
- public <_2Prime> Tuple2<_1, _2Prime> fmap(MonadicFunction super _2, ? extends _2Prime> fn) {
+ public <_2Prime> Tuple2<_1, _2Prime> fmap(Fn1 super _2, ? extends _2Prime> fn) {
return tuple(_1(), fn.apply(_2()));
}
@Override
@SuppressWarnings("unchecked")
- public <_1Prime> Tuple2<_1Prime, _2> biMapL(MonadicFunction super _1, ? extends _1Prime> fn) {
+ public <_1Prime> Tuple2<_1Prime, _2> biMapL(Fn1 super _1, ? extends _1Prime> fn) {
return (Tuple2<_1Prime, _2>) Bifunctor.super.biMapL(fn);
}
@Override
@SuppressWarnings("unchecked")
- public <_2Prime> Tuple2<_1, _2Prime> biMapR(MonadicFunction super _2, ? extends _2Prime> fn) {
+ public <_2Prime> Tuple2<_1, _2Prime> biMapR(Fn1 super _2, ? extends _2Prime> fn) {
return (Tuple2<_1, _2Prime>) Bifunctor.super.biMapR(fn);
}
@Override
- public <_1Prime, _2Prime> Tuple2<_1Prime, _2Prime> biMap(MonadicFunction super _1, ? extends _1Prime> lFn,
- MonadicFunction super _2, ? extends _2Prime> rFn) {
+ public <_1Prime, _2Prime> Tuple2<_1Prime, _2Prime> biMap(Fn1 super _1, ? extends _1Prime> lFn,
+ Fn1 super _2, ? extends _2Prime> rFn) {
return new Tuple2<>(lFn.apply(_1()), tail().fmap(rFn));
}
+ /**
+ * Static factory method for creating Tuple2s from {@link java.util.Map.Entry}s.
+ *
+ * @param entry the map entry
+ * @param the key parameter type, and first (head) element type
+ * @param the value parameter type, and second element type
+ * @return the newly created Tuple2
+ */
public static Tuple2 fromEntry(Map.Entry entry) {
- return new Tuple2<>(entry.getKey(), singleton(entry.getValue()));
+ return new Tuple2<>(entry.getKey(), singletonHList(entry.getValue()));
}
}
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java
index 45c711b1d..acc840e06 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java
@@ -1,25 +1,32 @@
package com.jnape.palatable.lambda.adt.hlist;
import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
-import com.jnape.palatable.lambda.functions.MonadicFunction;
+import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functor.Bifunctor;
import com.jnape.palatable.lambda.functor.Functor;
/**
- * A 3-element tuple product type, implemented as a specialized HList.
+ * A 3-element tuple product type, implemented as a specialized HList. Supports random access.
*
* @param <_1> The first slot element type
* @param <_2> The second slot element type
* @param <_3> The third slot element type
* @see HList
- * @see Singleton
+ * @see SingletonHList
* @see Tuple2
* @see Tuple4
* @see Tuple5
*/
-public final class Tuple3<_1, _2, _3> extends HCons<_1, Tuple2<_2, _3>> implements Functor<_3>, Bifunctor<_2, _3> {
+public class Tuple3<_1, _2, _3> extends HCons<_1, Tuple2<_2, _3>> implements Functor<_3>, Bifunctor<_2, _3> {
+ private final _1 _1;
+ private final _2 _2;
+ private final _3 _3;
+
Tuple3(_1 _1, Tuple2<_2, _3> tail) {
super(_1, tail);
+ this._1 = _1;
+ _2 = tail._1();
+ _3 = tail._2();
}
@Override
@@ -27,38 +34,53 @@ public <_0> Tuple4<_0, _1, _2, _3> cons(_0 _0) {
return new Tuple4<>(_0, this);
}
+ /**
+ * Retrieve the first (head) element in constant time.
+ *
+ * @return the head element
+ */
public _1 _1() {
- return head();
+ return _1;
}
+ /**
+ * Retrieve the second element in constant time.
+ *
+ * @return the second element
+ */
public _2 _2() {
- return tail()._1();
+ return _2;
}
+ /**
+ * Retrieve the third element in constant time.
+ *
+ * @return the third element
+ */
public _3 _3() {
- return tail()._2();
+ return _3;
}
@Override
- public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(MonadicFunction super _3, ? extends _3Prime> fn) {
+ public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Fn1 super _3, ? extends _3Prime> fn) {
return biMapR(fn);
}
@Override
@SuppressWarnings("unchecked")
- public <_2Prime> Tuple3<_1, _2Prime, _3> biMapL(MonadicFunction super _2, ? extends _2Prime> fn) {
+ public <_2Prime> Tuple3<_1, _2Prime, _3> biMapL(Fn1 super _2, ? extends _2Prime> fn) {
return (Tuple3<_1, _2Prime, _3>) Bifunctor.super.biMapL(fn);
}
@Override
@SuppressWarnings("unchecked")
- public <_3Prime> Tuple3<_1, _2, _3Prime> biMapR(MonadicFunction super _3, ? extends _3Prime> fn) {
+ public <_3Prime> Tuple3<_1, _2, _3Prime> biMapR(Fn1 super _3, ? extends _3Prime> fn) {
return (Tuple3<_1, _2, _3Prime>) Bifunctor.super.biMapR(fn);
}
@Override
- public <_2Prime, _3Prime> Tuple3<_1, _2Prime, _3Prime> biMap(MonadicFunction super _2, ? extends _2Prime> lFn,
- MonadicFunction super _3, ? extends _3Prime> rFn) {
+ public <_2Prime, _3Prime> Tuple3<_1, _2Prime, _3Prime> biMap(Fn1 super _2, ? extends _2Prime> lFn,
+ Fn1 super _3, ? extends _3Prime> rFn) {
return new Tuple3<>(_1(), tail().biMap(lFn, rFn));
}
}
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple4.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple4.java
index 1e655389f..38208b713 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple4.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple4.java
@@ -1,26 +1,35 @@
package com.jnape.palatable.lambda.adt.hlist;
import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
-import com.jnape.palatable.lambda.functions.MonadicFunction;
+import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functor.Bifunctor;
import com.jnape.palatable.lambda.functor.Functor;
/**
- * A 4-element tuple product type, implemented as a specialized HList.
+ * A 4-element tuple product type, implemented as a specialized HList. Supports random access.
*
* @param <_1> The first slot element type
* @param <_2> The second slot element type
* @param <_3> The third slot element type
* @param <_4> The fourth slot element type
* @see HList
- * @see Singleton
+ * @see SingletonHList
* @see Tuple2
* @see Tuple3
* @see Tuple5
*/
-public final class Tuple4<_1, _2, _3, _4> extends HCons<_1, Tuple3<_2, _3, _4>> implements Functor<_4>, Bifunctor<_3, _4> {
+public class Tuple4<_1, _2, _3, _4> extends HCons<_1, Tuple3<_2, _3, _4>> implements Functor<_4>, Bifunctor<_3, _4> {
+ private final _1 _1;
+ private final _2 _2;
+ private final _3 _3;
+ private final _4 _4;
+
Tuple4(_1 _1, Tuple3<_2, _3, _4> tail) {
super(_1, tail);
+ this._1 = _1;
+ _2 = tail._1();
+ _3 = tail._2();
+ _4 = tail._3();
}
@Override
@@ -28,42 +37,62 @@ public <_0> Tuple5<_0, _1, _2, _3, _4> cons(_0 _0) {
return new Tuple5<>(_0, this);
}
+ /**
+ * Retrieve the first (head) element in constant time.
+ *
+ * @return the head element
+ */
public _1 _1() {
- return head();
+ return _1;
}
+ /**
+ * Retrieve the second element in constant time.
+ *
+ * @return the second element
+ */
public _2 _2() {
- return tail()._1();
+ return _2;
}
+ /**
+ * Retrieve the third element in constant time.
+ *
+ * @return the third element
+ */
public _3 _3() {
- return tail()._2();
+ return _3;
}
+ /**
+ * Retrieve the fourth element in constant time.
+ *
+ * @return the fourth element
+ */
public _4 _4() {
- return tail()._3();
+ return _4;
}
@Override
- public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(MonadicFunction super _4, ? extends _4Prime> fn) {
+ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(Fn1 super _4, ? extends _4Prime> fn) {
return biMapR(fn);
}
@Override
@SuppressWarnings("unchecked")
- public <_3Prime> Tuple4<_1, _2, _3Prime, _4> biMapL(MonadicFunction super _3, ? extends _3Prime> fn) {
+ public <_3Prime> Tuple4<_1, _2, _3Prime, _4> biMapL(Fn1 super _3, ? extends _3Prime> fn) {
return (Tuple4<_1, _2, _3Prime, _4>) Bifunctor.super.biMapL(fn);
}
@Override
@SuppressWarnings("unchecked")
- public <_4Prime> Tuple4<_1, _2, _3, _4Prime> biMapR(MonadicFunction super _4, ? extends _4Prime> fn) {
+ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> biMapR(Fn1 super _4, ? extends _4Prime> fn) {
return (Tuple4<_1, _2, _3, _4Prime>) Bifunctor.super.biMapR(fn);
}
@Override
- public <_3Prime, _4Prime> Tuple4<_1, _2, _3Prime, _4Prime> biMap(MonadicFunction super _3, ? extends _3Prime> lFn,
- MonadicFunction super _4, ? extends _4Prime> rFn) {
+ public <_3Prime, _4Prime> Tuple4<_1, _2, _3Prime, _4Prime> biMap(Fn1 super _3, ? extends _3Prime> lFn,
+ Fn1 super _4, ? extends _4Prime> rFn) {
return new Tuple4<>(_1(), tail().biMap(lFn, rFn));
}
}
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple5.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple5.java
index ead0b387f..49cf2c29a 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple5.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple5.java
@@ -1,12 +1,12 @@
package com.jnape.palatable.lambda.adt.hlist;
import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
-import com.jnape.palatable.lambda.functions.MonadicFunction;
+import com.jnape.palatable.lambda.functions.Fn1;
import com.jnape.palatable.lambda.functor.Bifunctor;
import com.jnape.palatable.lambda.functor.Functor;
/**
- * A 5-element tuple product type, implemented as a specialized HList.
+ * A 5-element tuple product type, implemented as a specialized HList. Supports random access.
*
* @param <_1> The first slot element type
* @param <_2> The second slot element type
@@ -14,14 +14,25 @@
* @param <_4> The fourth slot element type
* @param <_5> The fifth slot element type
* @see HList
- * @see Singleton
+ * @see SingletonHList
* @see Tuple2
* @see Tuple3
* @see Tuple4
*/
-public final class Tuple5<_1, _2, _3, _4, _5> extends HCons<_1, Tuple4<_2, _3, _4, _5>> implements Functor<_5>, Bifunctor<_4, _5> {
- Tuple5(_1 a, Tuple4<_2, _3, _4, _5> tail) {
- super(a, tail);
+public class Tuple5<_1, _2, _3, _4, _5> extends HCons<_1, Tuple4<_2, _3, _4, _5>> implements Functor<_5>, Bifunctor<_4, _5> {
+ private final _1 _1;
+ private final _2 _2;
+ private final _3 _3;
+ private final _4 _4;
+ private final _5 _5;
+
+ Tuple5(_1 _1, Tuple4<_2, _3, _4, _5> tail) {
+ super(_1, tail);
+ this._1 = _1;
+ _2 = tail._1();
+ _3 = tail._2();
+ _4 = tail._3();
+ _5 = tail._4();
}
@Override
@@ -29,47 +40,71 @@ public <_0> HCons<_0, Tuple5<_1, _2, _3, _4, _5>> cons(_0 _0) {
return new HCons<>(_0, this);
}
+ /**
+ * Retrieve the first (head) element in constant time.
+ *
+ * @return the head element
+ */
public _1 _1() {
- return head();
+ return _1;
}
+ /**
+ * Retrieve the second element in constant time.
+ *
+ * @return the second element
+ */
public _2 _2() {
- return tail()._1();
+ return _2;
}
+ /**
+ * Retrieve the third element in constant time.
+ *
+ * @return the third element
+ */
public _3 _3() {
- return tail()._2();
+ return _3;
}
+ /**
+ * Retrieve the fourth element in constant time.
+ *
+ * @return the fourth element
+ */
public _4 _4() {
- return tail()._3();
+ return _4;
}
+ /**
+ * Retrieve the fifth element in constant time.
+ *
+ * @return the fifth element
+ */
public _5 _5() {
- return tail()._4();
+ return _5;
}
@Override
- public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(MonadicFunction super _5, ? extends _5Prime> fn) {
+ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Fn1 super _5, ? extends _5Prime> fn) {
return biMapR(fn);
}
@Override
@SuppressWarnings("unchecked")
- public <_4Prime> Tuple5<_1, _2, _3, _4Prime, _5> biMapL(MonadicFunction super _4, ? extends _4Prime> fn) {
+ public <_4Prime> Tuple5<_1, _2, _3, _4Prime, _5> biMapL(Fn1 super _4, ? extends _4Prime> fn) {
return (Tuple5<_1, _2, _3, _4Prime, _5>) Bifunctor.super.biMapL(fn);
}
@Override
@SuppressWarnings("unchecked")
- public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> biMapR(MonadicFunction super _5, ? extends _5Prime> fn) {
+ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> biMapR(Fn1 super _5, ? extends _5Prime> fn) {
return (Tuple5<_1, _2, _3, _4, _5Prime>) Bifunctor.super.biMapR(fn);
}
@Override
- public <_4Prime, _5Prime> Tuple5<_1, _2, _3, _4Prime, _5Prime> biMap(
- MonadicFunction super _4, ? extends _4Prime> lFn,
- MonadicFunction super _5, ? extends _5Prime> rFn) {
+ public <_4Prime, _5Prime> Tuple5<_1, _2, _3, _4Prime, _5Prime> biMap(Fn1 super _4, ? extends _4Prime> lFn,
+ Fn1 super _5, ? extends _5Prime> rFn) {
return new Tuple5<>(_1(), tail().biMap(lFn, rFn));
}
}
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/HMap.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/HMap.java
index 537f61dc5..ba15852e3 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/HMap.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/HMap.java
@@ -10,12 +10,13 @@
import java.util.Optional;
import java.util.function.Consumer;
-import static com.jnape.palatable.lambda.functions.builtin.dyadic.Map.map;
+import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
/**
- * A heterogeneous mapping from a parametrized type-safe key to any value, supporting a minimal mapping interface.
+ * An immutable heterogeneous mapping from a parametrized type-safe key to any value, supporting a minimal mapping
+ * interface.
*
* @see TypeSafeKey
* @see com.jnape.palatable.lambda.adt.hlist.HList
@@ -30,31 +31,76 @@ public class HMap implements Iterable> {
this.table = table;
}
+ /**
+ * Retrieve the value at this key.
+ *
+ * @param key the key
+ * @param the value type
+ * @return the value at this key wrapped in an {@link Optional}, or {@link Optional#empty}.
+ */
@SuppressWarnings("unchecked")
public Optional get(TypeSafeKey key) {
return Optional.ofNullable((T) table.get(key));
}
- public V demand(TypeSafeKey key) {
+ /**
+ * Retrieve the value at this key, throwing a {@link NoSuchElementException} if this key is unmapped.
+ *
+ * @param key the key
+ * @param the value type
+ * @return the value at this key
+ * @throws NoSuchElementException if the key is unmapped
+ */
+ public V demand(TypeSafeKey key) throws NoSuchElementException {
return get(key).orElseThrow(() -> new NoSuchElementException("Demanded value for key " + key + ", but couldn't find one."));
}
+ /**
+ * Store a value for the given key.
+ *
+ * @param key the key
+ * @param value the value
+ * @param the value type
+ * @return the updated HMap
+ */
public HMap put(TypeSafeKey key, V value) {
return alter(t -> t.put(key, value));
}
+ /**
+ * Store all the key/value mappings in hMap in this HMap.
+ *
+ * @param hMap the other hMap
+ * @return the updated HMap
+ */
public HMap putAll(HMap hMap) {
return alter(t -> t.putAll(hMap.table));
}
+ /**
+ * Determine if a key is mapped.
+ *
+ * @param key the key
+ * @return true if the key is mapped; false otherwise
+ */
public boolean containsKey(TypeSafeKey key) {
return table.containsKey(key);
}
+ /**
+ * Retrieve all the mapped keys.
+ *
+ * @return an Iterable of all the mapped keys
+ */
public Iterable keys() {
return map(Tuple2::_1, this);
}
+ /**
+ * Retrieve all the mapped values.
+ *
+ * @return an Iterable of all the mapped values
+ */
public Iterable