diff --git a/CHANGELOG.md b/CHANGELOG.md
index c61bcb6c0..98efd8a2e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
## [Unreleased]
### Added
+- `Lens#toIso`, for converting a lens to an iso
+- `HMap#hMap` overloads up to 8 bindings deep
+- `Schema`, schemas for extracting multiple values from `HMap`s by aggregating `TypeSafeKey`s
+
+### Fixed
+- Deforested iterables execute in intended nesting order, where essential
+
+## [3.0.2] - 2018-05-21
+### Added
- `IterableLens#mapping`, an `Iso` that maps values
### Changed
@@ -323,7 +332,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
- `Monadic/Dyadic/TriadicFunction`, `Predicate`, `Tuple2`, `Tuple3`
- `Functor`, `BiFunctor`, `ProFunctor`
-[Unreleased]: https://github.com/palatable/lambda/compare/lambda-3.0.1...HEAD
+[Unreleased]: https://github.com/palatable/lambda/compare/lambda-3.0.2...HEAD
+[3.0.2]: https://github.com/palatable/lambda/compare/lambda-3.0.1...lambda-3.0.2
[3.0.1]: https://github.com/palatable/lambda/compare/lambda-3.0.0...lambda-3.0.1
[3.0.0]: https://github.com/palatable/lambda/compare/lambda-2.1.1...lambda-3.0.0
[2.1.1]: https://github.com/palatable/lambda/compare/lambda-2.1.0...lambda-2.1.1
diff --git a/README.md b/README.md
index a08d8dcc8..1d889d106 100644
--- a/README.md
+++ b/README.md
@@ -57,14 +57,14 @@ Add the following dependency to your:
com.jnape.palatable
lambda
- 3.0.1
+ 3.0.2
```
`build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)):
```gradle
-compile group: 'com.jnape.palatable', name: 'lambda', version: '3.0.1'
+compile group: 'com.jnape.palatable', name: 'lambda', version: '3.0.2'
```
Examples
@@ -444,8 +444,7 @@ Examples of traversable functors include:
- `Choice*`
- `Either`
- `Const` and `Identity`
-- `TraversableIterable` for wrapping `Iterable` in an instance of `Traversable`
-- `TraversableOptional` for wrapping `Optional` in an instance of `Traversable`
+- `LambdaIterable` for wrapping `Iterable` in an instance of `Traversable`
In addition to implementing `fmap` from `Functor`, implementing a traversable functor involves providing an implementation of `traverse`.
diff --git a/pom.xml b/pom.xml
index ac48a3a91..3f4928797 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
lambda
- 3.0.2
+ 3.0.3
jar
Lambda
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 e2e3fd3c1..21de6c983 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
@@ -19,7 +19,6 @@
import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map;
import static com.jnape.palatable.lambda.lens.functions.View.view;
import static java.util.Collections.emptyMap;
-import static java.util.Collections.singletonMap;
/**
* An immutable heterogeneous mapping from a parametrized type-safe key to any value, supporting a minimal mapping
@@ -232,6 +231,194 @@ public static HMap hMap(TypeSafeKey, V1> key1, V1 value1,
public static HMap hMap(TypeSafeKey, V1> key1, V1 value1,
TypeSafeKey, V2> key2, V2 value2,
TypeSafeKey, V3> key3, V3 value3) {
- return hMap(key1, value1, key2, value2).put(key3, value3);
+ return hMap(key1, value1,
+ key2, value2)
+ .put(key3, value3);
}
+
+ /**
+ * Static factory method for creating an HMap from four given associations.
+ *
+ * @param key1 the first mapped key
+ * @param value1 the value mapped at key1
+ * @param key2 the second mapped key
+ * @param value2 the value mapped at key2
+ * @param key3 the third mapped key
+ * @param value3 the value mapped at key3
+ * @param key4 the fourth mapped key
+ * @param value4 the value mapped at key4
+ * @param value1's type
+ * @param value2's type
+ * @param value3's type
+ * @param value4's type
+ * @return an HMap with the given associations
+ */
+ public static HMap hMap(TypeSafeKey, V1> key1, V1 value1,
+ TypeSafeKey, V2> key2, V2 value2,
+ TypeSafeKey, V3> key3, V3 value3,
+ TypeSafeKey, V4> key4, V4 value4) {
+ return hMap(key1, value1,
+ key2, value2,
+ key3, value3)
+ .put(key4, value4);
+ }
+
+ /**
+ * Static factory method for creating an HMap from five given associations.
+ *
+ * @param key1 the first mapped key
+ * @param value1 the value mapped at key1
+ * @param key2 the second mapped key
+ * @param value2 the value mapped at key2
+ * @param key3 the third mapped key
+ * @param value3 the value mapped at key3
+ * @param key4 the fourth mapped key
+ * @param value4 the value mapped at key4
+ * @param key5 the fifth mapped key
+ * @param value5 the value mapped at key5
+ * @param value1's type
+ * @param value2's type
+ * @param value3's type
+ * @param value4's type
+ * @param value5's type
+ * @return an HMap with the given associations
+ */
+ public static HMap hMap(TypeSafeKey, V1> key1, V1 value1,
+ TypeSafeKey, V2> key2, V2 value2,
+ TypeSafeKey, V3> key3, V3 value3,
+ TypeSafeKey, V4> key4, V4 value4,
+ TypeSafeKey, V5> key5, V5 value5) {
+ return hMap(key1, value1,
+ key2, value2,
+ key3, value3,
+ key4, value4)
+ .put(key5, value5);
+ }
+
+ /**
+ * Static factory method for creating an HMap from six given associations.
+ *
+ * @param key1 the first mapped key
+ * @param value1 the value mapped at key1
+ * @param key2 the second mapped key
+ * @param value2 the value mapped at key2
+ * @param key3 the third mapped key
+ * @param value3 the value mapped at key3
+ * @param key4 the fourth mapped key
+ * @param value4 the value mapped at key4
+ * @param key5 the fifth mapped key
+ * @param value5 the value mapped at key5
+ * @param key6 the sixth mapped key
+ * @param value6 the value mapped at key6
+ * @param value1's type
+ * @param value2's type
+ * @param value3's type
+ * @param value4's type
+ * @param value5's type
+ * @param value6's type
+ * @return an HMap with the given associations
+ */
+ public static HMap hMap(TypeSafeKey, V1> key1, V1 value1,
+ TypeSafeKey, V2> key2, V2 value2,
+ TypeSafeKey, V3> key3, V3 value3,
+ TypeSafeKey, V4> key4, V4 value4,
+ TypeSafeKey, V5> key5, V5 value5,
+ TypeSafeKey, V6> key6, V6 value6) {
+ return hMap(key1, value1,
+ key2, value2,
+ key3, value3,
+ key4, value4,
+ key5, value5)
+ .put(key6, value6);
+ }
+
+ /**
+ * Static factory method for creating an HMap from seven given associations.
+ *
+ * @param key1 the first mapped key
+ * @param value1 the value mapped at key1
+ * @param key2 the second mapped key
+ * @param value2 the value mapped at key2
+ * @param key3 the third mapped key
+ * @param value3 the value mapped at key3
+ * @param key4 the fourth mapped key
+ * @param value4 the value mapped at key4
+ * @param key5 the fifth mapped key
+ * @param value5 the value mapped at key5
+ * @param key6 the sixth mapped key
+ * @param value6 the value mapped at key6
+ * @param key7 the seventh mapped key
+ * @param value7 the value mapped at key7
+ * @param value1's type
+ * @param value2's type
+ * @param value3's type
+ * @param value4's type
+ * @param value5's type
+ * @param value6's type
+ * @param value7's type
+ * @return an HMap with the given associations
+ */
+ public static HMap hMap(TypeSafeKey, V1> key1, V1 value1,
+ TypeSafeKey, V2> key2, V2 value2,
+ TypeSafeKey, V3> key3, V3 value3,
+ TypeSafeKey, V4> key4, V4 value4,
+ TypeSafeKey, V5> key5, V5 value5,
+ TypeSafeKey, V6> key6, V6 value6,
+ TypeSafeKey, V7> key7, V7 value7) {
+ return hMap(key1, value1,
+ key2, value2,
+ key3, value3,
+ key4, value4,
+ key5, value5,
+ key6, value6)
+ .put(key7, value7);
+ }
+
+ /**
+ * Static factory method for creating an HMap from eight given associations.
+ *
+ * @param key1 the first mapped key
+ * @param value1 the value mapped at key1
+ * @param key2 the second mapped key
+ * @param value2 the value mapped at key2
+ * @param key3 the third mapped key
+ * @param value3 the value mapped at key3
+ * @param key4 the fourth mapped key
+ * @param value4 the value mapped at key4
+ * @param key5 the fifth mapped key
+ * @param value5 the value mapped at key5
+ * @param key6 the sixth mapped key
+ * @param value6 the value mapped at key6
+ * @param key7 the seventh mapped key
+ * @param value7 the value mapped at key7
+ * @param key8 the eighth mapped key
+ * @param value8 the value mapped at key8
+ * @param value1's type
+ * @param value2's type
+ * @param value3's type
+ * @param value4's type
+ * @param value5's type
+ * @param value6's type
+ * @param value7's type
+ * @param value8's type
+ * @return an HMap with the given associations
+ */
+ public static HMap hMap(TypeSafeKey, V1> key1, V1 value1,
+ TypeSafeKey, V2> key2, V2 value2,
+ TypeSafeKey, V3> key3, V3 value3,
+ TypeSafeKey, V4> key4, V4 value4,
+ TypeSafeKey, V5> key5, V5 value5,
+ TypeSafeKey, V6> key6, V6 value6,
+ TypeSafeKey, V7> key7, V7 value7,
+ TypeSafeKey, V8> key8, V8 value8) {
+ return hMap(key1, value1,
+ key2, value2,
+ key3, value3,
+ key4, value4,
+ key5, value5,
+ key6, value6,
+ key7, value7)
+ .put(key8, value8);
+ }
+
}
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java
new file mode 100644
index 000000000..52e4b0903
--- /dev/null
+++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java
@@ -0,0 +1,94 @@
+package com.jnape.palatable.lambda.adt.hmap;
+
+import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.adt.hlist.HList;
+import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
+import com.jnape.palatable.lambda.adt.hlist.SingletonHList;
+import com.jnape.palatable.lambda.adt.hlist.Tuple2;
+import com.jnape.palatable.lambda.adt.hlist.Tuple3;
+import com.jnape.palatable.lambda.adt.hlist.Tuple4;
+import com.jnape.palatable.lambda.adt.hlist.Tuple5;
+import com.jnape.palatable.lambda.adt.hlist.Tuple6;
+import com.jnape.palatable.lambda.adt.hlist.Tuple7;
+import com.jnape.palatable.lambda.adt.hlist.Tuple8;
+import com.jnape.palatable.lambda.functions.builtin.fn2.Both;
+import com.jnape.palatable.lambda.lens.Lens;
+
+import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
+import static com.jnape.palatable.lambda.lens.lenses.HMapLens.valueAt;
+
+public interface Schema> extends Lens.Simple> {
+
+ @SuppressWarnings("unchecked")
+ default > Schema add(TypeSafeKey, A> key) {
+ return Lens.both(this, valueAt(key))
+ .>mapA(into((maybeValues, maybeA) -> maybeValues.zip(maybeA.fmap(a -> values -> (NewValues) values.cons(a)))))
+ .>mapB(Both.both(maybeNewValues -> maybeNewValues.fmap(HCons::tail),
+ maybeNewValues -> maybeNewValues.fmap(HCons::head)))
+ ::apply;
+ }
+
+ static Schema> schema(TypeSafeKey, A> key) {
+ return valueAt(key)
+ .mapA(ma -> ma.fmap(HList::singletonHList))
+ .>>mapB(maybeSingletonA -> maybeSingletonA.fmap(HCons::head))
+ ::apply;
+ }
+
+ static Schema> schema(TypeSafeKey, A> aKey,
+ TypeSafeKey, B> bKey) {
+ return schema(bKey).add(aKey);
+ }
+
+ static Schema> schema(TypeSafeKey, A> aKey,
+ TypeSafeKey, B> bKey,
+ TypeSafeKey, C> cKey) {
+ return schema(bKey, cKey).add(aKey);
+ }
+
+ static Schema> schema(TypeSafeKey, A> aKey,
+ TypeSafeKey, B> bKey,
+ TypeSafeKey, C> cKey,
+ TypeSafeKey, D> dKey) {
+ return schema(bKey, cKey, dKey).add(aKey);
+ }
+
+
+ static Schema> schema(TypeSafeKey, A> aKey,
+ TypeSafeKey, B> bKey,
+ TypeSafeKey, C> cKey,
+ TypeSafeKey, D> dKey,
+ TypeSafeKey, E> eKey) {
+ return schema(bKey, cKey, dKey, eKey).add(aKey);
+ }
+
+ static Schema> schema(TypeSafeKey, A> aKey,
+ TypeSafeKey, B> bKey,
+ TypeSafeKey, C> cKey,
+ TypeSafeKey, D> dKey,
+ TypeSafeKey, E> eKey,
+ TypeSafeKey, F> fKey) {
+ return schema(bKey, cKey, dKey, eKey, fKey).add(aKey);
+ }
+
+ static Schema> schema(TypeSafeKey, A> aKey,
+ TypeSafeKey, B> bKey,
+ TypeSafeKey, C> cKey,
+ TypeSafeKey, D> dKey,
+ TypeSafeKey, E> eKey,
+ TypeSafeKey, F> fKey,
+ TypeSafeKey, G> gKey) {
+ return schema(bKey, cKey, dKey, eKey, fKey, gKey).add(aKey);
+ }
+
+ static Schema> schema(TypeSafeKey, A> aKey,
+ TypeSafeKey, B> bKey,
+ TypeSafeKey, C> cKey,
+ TypeSafeKey, D> dKey,
+ TypeSafeKey, E> eKey,
+ TypeSafeKey, F> fKey,
+ TypeSafeKey, G> gKey,
+ TypeSafeKey, H> hKey) {
+ return schema(bKey, cKey, dKey, eKey, fKey, gKey, hKey).add(aKey);
+ }
+}
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java
index bd7be982c..4d3096051 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java
@@ -16,7 +16,7 @@ public FilteringIterable(Function super A, Boolean> predicate, Iterable as)
List> predicates = new ArrayList<>(singletonList(predicate));
while (as instanceof FilteringIterable) {
FilteringIterable nested = (FilteringIterable) as;
- predicates.addAll(nested.predicates);
+ predicates.addAll(0, nested.predicates);
as = nested.as;
}
this.predicates = predicates;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java
index e4b2ca429..10338ca7c 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java
@@ -18,7 +18,7 @@ public PredicatedDroppingIterable(Function super A, Boolean> predicate, Iterab
while (as instanceof PredicatedDroppingIterable) {
PredicatedDroppingIterable nested = (PredicatedDroppingIterable) as;
as = nested.as;
- predicates.addAll(nested.predicates);
+ predicates.addAll(0, nested.predicates);
}
this.predicates = predicates;
this.as = as;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java
index 4c80ccdb8..dc15675a7 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java
@@ -16,8 +16,8 @@ public PredicatedTakingIterable(Function super A, Boolean> predicate, Iterable
List> predicates = new ArrayList<>(singletonList(predicate));
while (as instanceof PredicatedTakingIterable) {
PredicatedTakingIterable nested = (PredicatedTakingIterable) as;
+ predicates.addAll(0, nested.predicates);
as = nested.as;
- predicates.addAll(nested.predicates);
}
this.predicates = predicates;
this.as = as;
diff --git a/src/main/java/com/jnape/palatable/lambda/lens/Lens.java b/src/main/java/com/jnape/palatable/lambda/lens/Lens.java
index 9b0f54774..3b5ac1f75 100644
--- a/src/main/java/com/jnape/palatable/lambda/lens/Lens.java
+++ b/src/main/java/com/jnape/palatable/lambda/lens/Lens.java
@@ -10,6 +10,7 @@
import java.util.function.BiFunction;
import java.util.function.Function;
+import static com.jnape.palatable.lambda.lens.Iso.iso;
import static com.jnape.palatable.lambda.lens.Lens.Simple.adapt;
import static com.jnape.palatable.lambda.lens.functions.Over.over;
import static com.jnape.palatable.lambda.lens.functions.Set.set;
@@ -209,6 +210,16 @@ default Lens mapB(Function super Z, ? extends B> fn) {
return lens(view(this), (s, z) -> set(this, fn.apply(z), s));
}
+ /**
+ * Produce an {@link Iso} from this {@link Lens} by providing a default S value.
+ *
+ * @param s the default S
+ * @return an {@link Iso}
+ */
+ default Iso toIso(S s) {
+ return iso(view(this), set(this).flip().apply(s));
+ }
+
/**
* Left-to-right composition of lenses. Requires compatibility between S and T.
*
diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java
index 682fd81bf..07e5e843a 100644
--- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java
@@ -113,21 +113,21 @@ public int hashCode() {
}
/**
- * Wrap an {@link Iterable} in a TraversableIterable.
+ * Wrap an {@link Iterable} in a {@link LambdaIterable}.
*
* @param as the Iterable
* @param the Iterable element type
- * @return the Iterable wrapped in a TraversableIterable
+ * @return the Iterable wrapped in a {@link LambdaIterable}
*/
public static LambdaIterable wrap(Iterable extends A> as) {
return new LambdaIterable<>(as);
}
/**
- * Construct an empty TraversableIterable by wrapping {@link java.util.Collections#emptyList()}.
+ * Construct an empty {@link LambdaIterable} by wrapping {@link java.util.Collections#emptyList()}.
*
* @param the Iterable element type
- * @return a TraversableIterable wrapping Collections.emptyList()
+ * @return a {@link LambdaIterable} wrapping Collections.emptyList()
*/
public static LambdaIterable empty() {
return wrap(emptyList());
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/HMapTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/HMapTest.java
index 65db8ee50..0c93ecb3f 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/HMapTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/HMapTest.java
@@ -191,18 +191,75 @@ public void values() {
@Test
public void convenienceStaticFactoryMethods() {
- TypeSafeKey stringKey = typeSafeKey();
- TypeSafeKey intKey = typeSafeKey();
- TypeSafeKey floatKey = typeSafeKey();
- assertEquals(emptyHMap().put(stringKey, "string value"),
+ TypeSafeKey.Simple stringKey = typeSafeKey();
+ TypeSafeKey.Simple intKey = typeSafeKey();
+ TypeSafeKey.Simple floatKey = typeSafeKey();
+ TypeSafeKey.Simple byteKey = typeSafeKey();
+ TypeSafeKey.Simple shortKey = typeSafeKey();
+ TypeSafeKey.Simple longKey = typeSafeKey();
+ TypeSafeKey.Simple doubleKey = typeSafeKey();
+ TypeSafeKey.Simple charKey = typeSafeKey();
+
+ HMap m1 = emptyHMap().put(stringKey, "string value");
+ HMap m2 = m1.put(intKey, 1);
+ HMap m3 = m2.put(floatKey, 1f);
+ HMap m4 = m3.put(byteKey, (byte) 1);
+ HMap m5 = m4.put(shortKey, (short) 1);
+ HMap m6 = m5.put(longKey, 1L);
+ HMap m7 = m6.put(doubleKey, 1D);
+ HMap m8 = m7.put(charKey, '1');
+
+ assertEquals(m1,
singletonHMap(stringKey, "string value"));
- assertEquals(emptyHMap().put(stringKey, "string value").put(intKey, 1),
+
+ assertEquals(m2,
hMap(stringKey, "string value",
intKey, 1));
- assertEquals(emptyHMap().put(stringKey, "string value").put(intKey, 1).put(floatKey, 1f),
+
+ assertEquals(m3,
hMap(stringKey, "string value",
intKey, 1,
floatKey, 1f));
+
+ assertEquals(m4,
+ hMap(stringKey, "string value",
+ intKey, 1,
+ floatKey, 1f,
+ byteKey, (byte) 1));
+
+ assertEquals(m5,
+ hMap(stringKey, "string value",
+ intKey, 1,
+ floatKey, 1f,
+ byteKey, (byte) 1,
+ shortKey, (short) 1));
+
+ assertEquals(m6,
+ hMap(stringKey, "string value",
+ intKey, 1,
+ floatKey, 1f,
+ byteKey, (byte) 1,
+ shortKey, (short) 1,
+ longKey, 1L));
+
+ assertEquals(m7,
+ hMap(stringKey, "string value",
+ intKey, 1,
+ floatKey, 1f,
+ byteKey, (byte) 1,
+ shortKey, (short) 1,
+ longKey, 1L,
+ doubleKey, 1D));
+
+ assertEquals(m8,
+ hMap(stringKey, "string value",
+ intKey, 1,
+ floatKey, 1f,
+ byteKey, (byte) 1,
+ shortKey, (short) 1,
+ longKey, 1L,
+ doubleKey, 1D,
+ charKey, '1'));
}
@Test
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java
new file mode 100644
index 000000000..5d76e50cd
--- /dev/null
+++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java
@@ -0,0 +1,50 @@
+package com.jnape.palatable.lambda.adt.hmap;
+
+import org.junit.Test;
+
+import static com.jnape.palatable.lambda.adt.Maybe.just;
+import static com.jnape.palatable.lambda.adt.Maybe.nothing;
+import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
+import static com.jnape.palatable.lambda.adt.hmap.HMap.emptyHMap;
+import static com.jnape.palatable.lambda.adt.hmap.HMap.hMap;
+import static com.jnape.palatable.lambda.adt.hmap.Schema.schema;
+import static com.jnape.palatable.lambda.adt.hmap.TypeSafeKey.typeSafeKey;
+import static com.jnape.palatable.lambda.lens.functions.View.view;
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static testsupport.assertion.LensAssert.assertLensLawfulness;
+
+public class SchemaTest {
+
+ @Test
+ public void extractsValuesAtKeysFromMap() {
+ TypeSafeKey.Simple byteKey = typeSafeKey();
+ TypeSafeKey.Simple shortKey = typeSafeKey();
+ TypeSafeKey.Simple intKey = typeSafeKey();
+ TypeSafeKey.Simple longKey = typeSafeKey();
+ TypeSafeKey.Simple floatKey = typeSafeKey();
+ TypeSafeKey.Simple doubleKey = typeSafeKey();
+ TypeSafeKey.Simple charKey = typeSafeKey();
+ TypeSafeKey.Simple booleanKey = typeSafeKey();
+
+ HMap m = hMap(byteKey, (byte) 1,
+ shortKey, (short) 2,
+ intKey, 3,
+ longKey, 4L,
+ floatKey, 5F,
+ doubleKey, 6D,
+ charKey, '7',
+ booleanKey, true);
+
+ assertLensLawfulness(schema(byteKey, shortKey, intKey, longKey, floatKey, doubleKey, charKey, booleanKey),
+ asList(emptyHMap(),
+ m),
+ asList(nothing(),
+ just(tuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, '7', true))));
+ }
+
+ @Test
+ public void extractsNothingIfAnyKeysMissing() {
+ assertEquals(nothing(), view(schema(typeSafeKey()), emptyHMap()));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/FlattenTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/FlattenTest.java
index d428e7c17..d1889525b 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/FlattenTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/FlattenTest.java
@@ -18,6 +18,7 @@
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
+import static java.util.Collections.singletonList;
import static org.junit.Assert.assertThat;
import static testsupport.matchers.IterableMatcher.isEmpty;
import static testsupport.matchers.IterableMatcher.iterates;
@@ -40,4 +41,10 @@ public void flattensSparseIterableOfPopulatedIterables() {
assertThat(flatten(asList(emptyList(), asList(1, 2, 3), emptyList(), emptyList(), singleton(4), asList(5, 6), emptyList())),
iterates(1, 2, 3, 4, 5, 6));
}
+
+ @Test
+ public void flattenMultipleLevelsOfNesting() {
+ assertThat(flatten(asList(asList(asList(1, 2, 3), asList(4, 5)), singletonList(asList(6, 7)))),
+ iterates(asList(1, 2, 3), asList(4, 5), asList(6, 7)));
+ }
}
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ReverseTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ReverseTest.java
index da6a94e45..308b9123e 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ReverseTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ReverseTest.java
@@ -37,7 +37,7 @@ public void iteratesElementsOfAnIterableBackwards() {
}
@Test
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({"unchecked", "ResultOfMethodCallIgnored"})
public void doesNotBeginReversingUntilIterated() {
Iterable mockIterable = mock(Iterable.class);
Iterator mockIterator = mock(Iterator.class);
@@ -50,4 +50,9 @@ public void doesNotBeginReversingUntilIterated() {
verify(mockIterator).hasNext();
verify(mockIterator, never()).next();
}
+
+ @Test
+ public void doubleReverseIsNoOp() {
+ assertThat(reverse(reverse(asList(1, 2, 3))), iterates(1, 2, 3));
+ }
}
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhileTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhileTest.java
index b57ae8085..e168d749a 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhileTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhileTest.java
@@ -11,7 +11,11 @@
import testsupport.traits.ImmutableIteration;
import testsupport.traits.Laziness;
+import java.util.ArrayList;
+import java.util.List;
+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
+import static com.jnape.palatable.lambda.functions.builtin.fn1.Force.force;
import static com.jnape.palatable.lambda.functions.builtin.fn2.DropWhile.dropWhile;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertThat;
@@ -41,4 +45,19 @@ public void dropsAllElementsIfPredicateNeverFails() {
public void dropsNoElementsIfPredicateImmediatelyFails() {
assertThat(dropWhile(constantly(false), asList(1, 2, 3)), iterates(1, 2, 3));
}
+
+ @Test
+ public void deforestingExecutesPredicatesInOrder() {
+ List innerInvocations = new ArrayList<>();
+ List outerInvocations = new ArrayList<>();
+ force(dropWhile(y -> {
+ outerInvocations.add(y);
+ return true;
+ }, dropWhile(x -> {
+ innerInvocations.add(x);
+ return x > 2;
+ }, asList(1, 2, 3))));
+ assertThat(innerInvocations, iterates(1, 2, 3));
+ assertThat(outerInvocations, iterates(1, 2));
+ }
}
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/FilterTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/FilterTest.java
index d718c55ef..27e5fa0bd 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/FilterTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/FilterTest.java
@@ -11,7 +11,11 @@
import testsupport.traits.ImmutableIteration;
import testsupport.traits.Laziness;
+import java.util.ArrayList;
+import java.util.List;
+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
+import static com.jnape.palatable.lambda.functions.builtin.fn1.Force.force;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertThat;
@@ -21,7 +25,7 @@
public class FilterTest {
@TestTraits({Laziness.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class})
- public Fn1 extends Iterable, ?> createTraitsTestSubject() {
+ public Fn1 extends Iterable, ?> testSubject() {
return filter(constantly(true));
}
@@ -33,4 +37,19 @@ public void filtersOutMatchingElements() {
iterates(2, 4, 6)
);
}
+
+ @Test
+ public void deforestingExecutesPredicatesInOrder() {
+ List innerInvocations = new ArrayList<>();
+ List outerInvocations = new ArrayList<>();
+ force(filter(y -> {
+ outerInvocations.add(y);
+ return true;
+ }, filter(x -> {
+ innerInvocations.add(x);
+ return x % 2 == 0;
+ }, asList(1, 2, 3))));
+ assertThat(innerInvocations, iterates(1, 2, 3));
+ assertThat(outerInvocations, iterates(2));
+ }
}
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SnocTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SnocTest.java
index 8615a5dd8..439a60dfd 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SnocTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SnocTest.java
@@ -15,6 +15,7 @@
import static com.jnape.palatable.lambda.functions.builtin.fn2.Snoc.snoc;
import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
import static org.junit.Assert.assertThat;
import static testsupport.matchers.IterableMatcher.iterates;
@@ -35,4 +36,9 @@ public void appendToEmptyIterable() {
public void appendToNonEmptyIterable() {
assertThat(snoc(4, asList(1, 2, 3)), iterates(1, 2, 3, 4));
}
+
+ @Test
+ public void deforestingOrder() {
+ assertThat(snoc(3, snoc(2, snoc(1, emptyList()))), iterates(1, 2, 3));
+ }
}
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhileTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhileTest.java
index 871bd3a6e..bfa4e7000 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhileTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhileTest.java
@@ -11,7 +11,11 @@
import testsupport.traits.ImmutableIteration;
import testsupport.traits.Laziness;
+import java.util.ArrayList;
+import java.util.List;
+
import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
+import static com.jnape.palatable.lambda.functions.builtin.fn1.Force.force;
import static com.jnape.palatable.lambda.functions.builtin.fn2.TakeWhile.takeWhile;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertThat;
@@ -46,4 +50,19 @@ public void takesAllElementsIfPredicateNeverFails() {
public void takesNoElementsIfPredicateImmediatelyFails() {
assertThat(takeWhile(constantly(false), asList(1, 2, 3)), isEmpty());
}
+
+ @Test
+ public void deforestingExecutesPredicatesInOrder() {
+ List innerInvocations = new ArrayList<>();
+ List outerInvocations = new ArrayList<>();
+ force(takeWhile(y -> {
+ outerInvocations.add(y);
+ return true;
+ }, takeWhile(x -> {
+ innerInvocations.add(x);
+ return x < 3;
+ }, asList(1, 2, 3))));
+ assertThat(innerInvocations, iterates(1, 2, 3));
+ assertThat(outerInvocations, iterates(1, 2));
+ }
}
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/recursion/TrampolineTest.java b/src/test/java/com/jnape/palatable/lambda/functions/recursion/TrampolineTest.java
index 9aa9db414..9d8d9a0d2 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/recursion/TrampolineTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/recursion/TrampolineTest.java
@@ -1,7 +1,6 @@
package com.jnape.palatable.lambda.functions.recursion;
import com.jnape.palatable.lambda.adt.hlist.Tuple2;
-import com.jnape.palatable.lambda.functions.recursion.RecursiveResult;
import org.junit.Test;
import java.math.BigInteger;
@@ -9,11 +8,11 @@
import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
-import static java.math.BigInteger.ONE;
-import static org.junit.Assert.assertEquals;
import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.recurse;
import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate;
import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline;
+import static java.math.BigInteger.ONE;
+import static org.junit.Assert.assertEquals;
public class TrampolineTest {
diff --git a/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java b/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java
index 2ab9e8028..12d94b30c 100644
--- a/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java
@@ -103,4 +103,11 @@ public void bothForSimpleLenses() {
assertEquals(tuple(3, '3'), view(both(stringToInt, stringToChar), "3"));
assertEquals("133", set(both(stringToInt, stringToChar), tuple(3, '3'), "1"));
}
+
+ @Test
+ public void toIso() {
+ Iso, Set, String, Integer> iso = LENS.toIso(singletonList(""));
+ assertEquals("1", view(iso, asList("1", "2", "3")));
+ assertEquals(singleton(1), view(iso.mirror(), 1));
+ }
}
\ No newline at end of file