From de3e1a4a85e23d0c4b13c2ab0aaf85471dfec1d6 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 21 May 2018 01:43:23 -0500 Subject: [PATCH 1/8] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ac48a3a91..30b2efc86 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.0.2 + 3.0.3-SNAPSHOT jar Lambda From 90d147d5a43797a6a9501019685e121202b3db49 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 21 May 2018 01:47:41 -0500 Subject: [PATCH 2/8] Updating CHANGELOG and README to latest version --- CHANGELOG.md | 6 +++++- README.md | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c61bcb6c0..bc7040e7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] +No unreleased changes + +## [3.0.2] - 2018-05-21 ### Added - `IterableLens#mapping`, an `Iso` that maps values @@ -323,7 +326,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..20da36970 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 From b29cfee351f6c4eb717bc00d85a4412edea497bd Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 24 May 2018 18:30:19 -0500 Subject: [PATCH 3/8] Deforested iterables execute in intended nesting order, where essential --- CHANGELOG.md | 3 ++- .../lambda/iteration/FilteringIterable.java | 2 +- .../iteration/PredicatedDroppingIterable.java | 2 +- .../iteration/PredicatedTakingIterable.java | 2 +- .../functions/builtin/fn1/FlattenTest.java | 7 +++++++ .../functions/builtin/fn1/ReverseTest.java | 7 ++++++- .../functions/builtin/fn2/DropWhileTest.java | 19 +++++++++++++++++ .../functions/builtin/fn2/FilterTest.java | 21 ++++++++++++++++++- .../functions/builtin/fn2/SnocTest.java | 6 ++++++ .../functions/builtin/fn2/TakeWhileTest.java | 19 +++++++++++++++++ 10 files changed, 82 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc7040e7a..61966e8ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] -No unreleased changes +### Fixed +- Deforested iterables execute in intended nesting order, where essential ## [3.0.2] - 2018-05-21 ### Added 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 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 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 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/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 createTraitsTestSubject() { + public Fn1 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)); + } } From 6312a543e2f2a25470d6faefc19bc5f764a05bfa Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 24 May 2018 19:01:17 -0500 Subject: [PATCH 4/8] Fixing documentation referencing defunct TraversableIterable --- README.md | 3 +-- .../palatable/lambda/traversable/LambdaIterable.java | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 20da36970..1d889d106 100644 --- a/README.md +++ b/README.md @@ -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/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 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()); From 6c91e649e4e58850cb899b1de72a2f6d96ff4507 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 26 May 2018 16:55:22 -0500 Subject: [PATCH 5/8] Lens#toIso for converting a lens to an iso --- CHANGELOG.md | 3 +++ .../java/com/jnape/palatable/lambda/lens/Lens.java | 11 +++++++++++ .../com/jnape/palatable/lambda/lens/LensTest.java | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61966e8ce..67e88ee4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] +### Added +- `Lens#toIso`, for converting a lens to an iso + ### Fixed - Deforested iterables execute in intended nesting order, where essential 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 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/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 From e8f1888a576d9930510a956b7950f1068f9d8697 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 26 May 2018 17:31:13 -0500 Subject: [PATCH 6/8] More HMap#hMap overloads --- CHANGELOG.md | 1 + .../jnape/palatable/lambda/adt/hmap/HMap.java | 191 +++++++++++++++++- .../palatable/lambda/adt/hmap/HMapTest.java | 69 ++++++- 3 files changed, 253 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67e88ee4a..271444150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ 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 ### Fixed - Deforested iterables execute in intended nesting order, where essential 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 key1, V1 value1, public static HMap hMap(TypeSafeKey key1, V1 value1, TypeSafeKey key2, V2 value2, TypeSafeKey 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 key1, V1 value1, + TypeSafeKey key2, V2 value2, + TypeSafeKey key3, V3 value3, + TypeSafeKey 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 key1, V1 value1, + TypeSafeKey key2, V2 value2, + TypeSafeKey key3, V3 value3, + TypeSafeKey key4, V4 value4, + TypeSafeKey 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 key1, V1 value1, + TypeSafeKey key2, V2 value2, + TypeSafeKey key3, V3 value3, + TypeSafeKey key4, V4 value4, + TypeSafeKey key5, V5 value5, + TypeSafeKey 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 key1, V1 value1, + TypeSafeKey key2, V2 value2, + TypeSafeKey key3, V3 value3, + TypeSafeKey key4, V4 value4, + TypeSafeKey key5, V5 value5, + TypeSafeKey key6, V6 value6, + TypeSafeKey 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 key1, V1 value1, + TypeSafeKey key2, V2 value2, + TypeSafeKey key3, V3 value3, + TypeSafeKey key4, V4 value4, + TypeSafeKey key5, V5 value5, + TypeSafeKey key6, V6 value6, + TypeSafeKey key7, V7 value7, + TypeSafeKey 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/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 From 48ca23216074463f6aac50cca6227d6fe13f61f2 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 26 May 2018 18:53:40 -0500 Subject: [PATCH 7/8] Schema, for representing TSK schemas in HMaps --- CHANGELOG.md | 1 + .../palatable/lambda/adt/hmap/Schema.java | 94 +++++++++++++++++++ .../palatable/lambda/adt/hmap/SchemaTest.java | 50 ++++++++++ .../functions/recursion/TrampolineTest.java | 5 +- 4 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java create mode 100644 src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 271444150..98efd8a2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### 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 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 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 key) { + return valueAt(key) + .mapA(ma -> ma.fmap(HList::singletonHList)) + .>>mapB(maybeSingletonA -> maybeSingletonA.fmap(HCons::head)) + ::apply; + } + + static Schema> schema(TypeSafeKey aKey, + TypeSafeKey bKey) { + return schema(bKey).add(aKey); + } + + static Schema> schema(TypeSafeKey aKey, + TypeSafeKey bKey, + TypeSafeKey cKey) { + return schema(bKey, cKey).add(aKey); + } + + static Schema> schema(TypeSafeKey aKey, + TypeSafeKey bKey, + TypeSafeKey cKey, + TypeSafeKey dKey) { + return schema(bKey, cKey, dKey).add(aKey); + } + + + static Schema> schema(TypeSafeKey aKey, + TypeSafeKey bKey, + TypeSafeKey cKey, + TypeSafeKey dKey, + TypeSafeKey eKey) { + return schema(bKey, cKey, dKey, eKey).add(aKey); + } + + static Schema> schema(TypeSafeKey aKey, + TypeSafeKey bKey, + TypeSafeKey cKey, + TypeSafeKey dKey, + TypeSafeKey eKey, + TypeSafeKey fKey) { + return schema(bKey, cKey, dKey, eKey, fKey).add(aKey); + } + + static Schema> schema(TypeSafeKey aKey, + TypeSafeKey bKey, + TypeSafeKey cKey, + TypeSafeKey dKey, + TypeSafeKey eKey, + TypeSafeKey fKey, + TypeSafeKey gKey) { + return schema(bKey, cKey, dKey, eKey, fKey, gKey).add(aKey); + } + + static Schema> schema(TypeSafeKey aKey, + TypeSafeKey bKey, + TypeSafeKey cKey, + TypeSafeKey dKey, + TypeSafeKey eKey, + TypeSafeKey fKey, + TypeSafeKey gKey, + TypeSafeKey hKey) { + return schema(bKey, cKey, dKey, eKey, fKey, gKey, hKey).add(aKey); + } +} 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/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 { From d56a7052905c30431239c00344e6e42e99ba711e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 27 May 2018 17:38:08 -0500 Subject: [PATCH 8/8] [maven-release-plugin] prepare release lambda-3.0.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 30b2efc86..3f4928797 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.0.3-SNAPSHOT + 3.0.3 jar Lambda