From 04d738d8d88335ad2da4c5fa77cf3ffbf2e7b4ff Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 7 May 2018 21:27:41 -0500 Subject: [PATCH 001/348] ToMap is covariant in Entry position --- CHANGELOG.md | 3 ++- .../palatable/lambda/functions/builtin/fn2/ToMap.java | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3273cf69d..8eba9013e 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 changes_ +### Changed +- `ToMap` accepts an `Iterable` covariant in `Map.Entry` ## [3.0.0] - 2018-05-04 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java index fa69c61c5..1522720aa 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java @@ -17,7 +17,7 @@ * @param the value element type * @param the resulting map type */ -public final class ToMap> implements Fn2, Iterable>, M> { +public final class ToMap> implements Fn2, Iterable>, M> { private static final ToMap INSTANCE = new ToMap<>(); @@ -25,7 +25,7 @@ private ToMap() { } @Override - public M apply(Supplier mSupplier, Iterable> entries) { + public M apply(Supplier mSupplier, Iterable> entries) { return foldLeft((m, kv) -> { m.put(kv.getKey(), kv.getValue()); return m; @@ -37,11 +37,12 @@ public static > ToMap toMap() { return INSTANCE; } - public static > Fn1>, M> toMap(Supplier mSupplier) { + public static > Fn1>, M> toMap(Supplier mSupplier) { return ToMap.toMap().apply(mSupplier); } - public static > M toMap(Supplier mSupplier, Iterable> entries) { + public static > M toMap(Supplier mSupplier, + Iterable> entries) { return toMap(mSupplier).apply(entries); } } From 06131c6cf8832c1e72c667b04ab62e3d55d7cf4b Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 7 May 2018 22:20:58 -0500 Subject: [PATCH 002/348] Adding better docs for MapLens#mappingValues --- .../java/com/jnape/palatable/lambda/lens/lenses/MapLens.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java index cb393ac1f..f412c1161 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java @@ -176,6 +176,9 @@ public static Lens.Simple, Map> mappingValues(Functi /** * A lens that focuses on a map while mapping its values with the mapping {@link Iso}. + *

+ * Note that for this lens to be lawful, iso must be bijective: that is, every V must + * uniquely and invertibly map to exactly one V2. * * @param iso the mapping {@link Iso} * @param the key type From 700d6253da8afea5556a6911fb07f65e77cb80ae Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 7 May 2018 23:52:20 -0500 Subject: [PATCH 003/348] Adding Upcast --- CHANGELOG.md | 3 ++ .../lambda/functions/builtin/fn1/Upcast.java | 43 +++++++++++++++++++ .../functions/builtin/fn1/UpcastTest.java | 18 ++++++++ 3 files changed, 64 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UpcastTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 8eba9013e..2d96d17d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - `ToMap` accepts an `Iterable` covariant in `Map.Entry` +### Added +- `Upcast` for safely casting up a type hierarchy + ## [3.0.0] - 2018-05-04 ### Changed - ***Breaking Change***: `Sequence` now has two more type parameters to aid in inference diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java new file mode 100644 index 000000000..08f6fe519 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java @@ -0,0 +1,43 @@ +package com.jnape.palatable.lambda.functions.builtin.fn1; + +import com.jnape.palatable.lambda.functions.Fn1; + +/** + * Upcast a value of type B to a value of type A that B extends. This is + * principally useful when dealing with parametric types that are invariant in their parameters and a cast is + * necessary for compatibility purposes. + *

+ * Example: + *

+ * {@code
+ * Iterable have = new ArrayList<>();
+ * Iterable want = map(upcast(), have); // necessary due to invariance in parameter
+ * }
+ * 
+ *

+ * Note that this is universally safe. + * + * @param the covariant type + * @param the contravariant type + */ +public final class Upcast implements Fn1 { + + private static final Upcast INSTANCE = new Upcast<>(); + + private Upcast() { + } + + @Override + public B apply(A a) { + return a; + } + + @SuppressWarnings("unchecked") + public static Upcast upcast() { + return INSTANCE; + } + + public static B upcast(A a) { + return Upcast.upcast().apply(a); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UpcastTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UpcastTest.java new file mode 100644 index 000000000..a93d83537 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UpcastTest.java @@ -0,0 +1,18 @@ +package com.jnape.palatable.lambda.functions.builtin.fn1; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; +import static java.util.Arrays.asList; + +public class UpcastTest { + + @Test + @SuppressWarnings("unused") + public void castsUp() { + Upcast upcast = upcast(); + Iterable strings = asList("foo", "bar"); + Iterable charSequences = map(upcast, strings); + } +} \ No newline at end of file From dfbc3faca9653bb242b098e43805497d418bd5f3 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 11 May 2018 19:32:05 -0500 Subject: [PATCH 004/348] Adding SetLens, lenses that operate on Sets --- CHANGELOG.md | 1 + .../palatable/lambda/lens/lenses/SetLens.java | 51 +++++++++++++++++++ .../lambda/lens/lenses/SetLensTest.java | 41 +++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java create mode 100644 src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d96d17d0..e6a8e835b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `Upcast` for safely casting up a type hierarchy +- `SetLens`, lenses operating on `Set`s ## [3.0.0] - 2018-05-04 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java new file mode 100644 index 000000000..b48ceea24 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java @@ -0,0 +1,51 @@ +package com.jnape.palatable.lambda.lens.lenses; + +import com.jnape.palatable.lambda.lens.Lens; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.lens.Lens.simpleLens; + +/** + * Lenses that operate on {@link Set}s. + */ +public final class SetLens { + + private SetLens() { + } + + /** + * A lens that focuses on whether a {@link Set} contains some value a. Note that copyFn is + * used to avoid mutating the {@link Set} in question. + * + * @param copyFn the copy function + * @param a the value in question + * @param the value type + * @param the set to focus on + * @return a lens that focuses on a value's inclusion in a given {@link Set} + */ + public static > Lens.Simple contains( + Function copyFn, A a) { + return simpleLens(setA -> setA.contains(a), + (setA, include) -> { + SetA copy = copyFn.apply(setA); + if (include) copy.add(a); + else copy.remove(a); + return copy; + }); + } + + /** + * A lens that focuses on whether a {@link Set} contains some value a. Like {@link #contains(Function, + * Object)} but with an implicit copy function that produces {@link HashSet}s. + * + * @param a the value in question + * @param the value type + * @return a lens that focuses on a value's inclusion in a given {@link Set} + */ + public static Lens.Simple, Boolean> contains(A a) { + return contains(HashSet::new, a); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java b/src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java new file mode 100644 index 000000000..9421e50f6 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java @@ -0,0 +1,41 @@ +package com.jnape.palatable.lambda.lens.lenses; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.TreeSet; + +import static com.jnape.palatable.lambda.lens.functions.Set.set; +import static java.util.Arrays.asList; +import static java.util.Collections.emptySet; +import static java.util.Collections.singleton; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertThat; +import static testsupport.assertion.LensAssert.assertLensLawfulness; + +public class SetLensTest { + + @Test + public void containsWithCopyFn() { + assertLensLawfulness(SetLens.contains(HashSet::new, 1), + asList(emptySet(), + singleton(1), + singleton(2), + new HashSet<>(asList(1, 2)), + new HashSet<>(asList(2, 3))), + asList(true, false)); + assertThat(set(SetLens.contains(TreeSet::new, 1), true, emptySet()), instanceOf(TreeSet.class)); + } + + @Test + public void containsWithoutCopyFn() { + assertLensLawfulness(SetLens.contains(1), + asList(emptySet(), + singleton(1), + singleton(2), + new HashSet<>(asList(1, 2)), + new HashSet<>(asList(2, 3))), + asList(true, false)); + assertThat(set(SetLens.contains(1), true, emptySet()), instanceOf(HashSet.class)); + } +} \ No newline at end of file From 3da90978f1d756611ab5a4e0a8eced703f9a9f40 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 May 2018 14:10:49 -0500 Subject: [PATCH 005/348] RecursiveResult#invert returns a new RecursiveResult --- CHANGELOG.md | 1 + .../lambda/functions/recursion/RecursiveResult.java | 5 +++++ .../lambda/functions/recursion/RecursiveResultTest.java | 3 +-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6a8e835b..277bc13e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Changed - `ToMap` accepts an `Iterable` covariant in `Map.Entry` +- `RecursiveResult#invert` is also a `RecursiveResult` ### Added - `Upcast` for safely casting up a type hierarchy diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java index 555af77e5..7da780a1e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java @@ -23,6 +23,11 @@ public abstract class RecursiveResult implements CoProduct2 invert() { + return match(RecursiveResult::terminate, RecursiveResult::recurse); + } + @Override @SuppressWarnings("unchecked") public RecursiveResult biMapL(Function fn) { diff --git a/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java b/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java index 49b086466..b46f91f5d 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java @@ -1,6 +1,5 @@ package com.jnape.palatable.lambda.functions.recursion; -import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -10,9 +9,9 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import static com.jnape.palatable.traitor.framework.Subjects.subjects; 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.traitor.framework.Subjects.subjects; @RunWith(Traits.class) public class RecursiveResultTest { From 85a79ef1ce56687fa8012b3f560be492f464c469 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 May 2018 14:33:55 -0500 Subject: [PATCH 006/348] Short-circuiting in relevant monoids --- CHANGELOG.md | 2 ++ .../jnape/palatable/lambda/monoid/Monoid.java | 18 ++++++++++++++++++ .../palatable/lambda/monoid/builtin/And.java | 9 +++++++++ .../palatable/lambda/monoid/builtin/First.java | 7 +++++++ .../palatable/lambda/monoid/builtin/Or.java | 8 ++++++++ .../lambda/monoid/builtin/AndTest.java | 14 ++++++++++++++ .../lambda/monoid/builtin/FirstTest.java | 14 ++++++++++++++ .../lambda/monoid/builtin/OrTest.java | 14 ++++++++++++++ 8 files changed, 86 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 277bc13e6..8b7f3c547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - `ToMap` accepts an `Iterable` covariant in `Map.Entry` - `RecursiveResult#invert` is also a `RecursiveResult` +- `First`/`And`/`Or` monoids all utilize short-circuiting +- `Monoid#foldLeft/foldRight` delegate to `Monoid#reduceLeft/reduceRight`, respectively ### Added - `Upcast` for safely casting up a type hierarchy diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java index 9a2d9f266..1a18a2f8a 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java @@ -8,7 +8,9 @@ import java.util.function.Function; import java.util.function.Supplier; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Snoc.snoc; /** * A {@link Monoid} is the pairing of a {@link Semigroup} with an identity element. @@ -64,6 +66,22 @@ default A foldMap(Function fn, Iterable bs) { return reduceLeft(map(fn, bs)); } + /** + * {@inheritDoc} + */ + @Override + default A foldLeft(A a, Iterable as) { + return reduceLeft(cons(a, as)); + } + + /** + * {@inheritDoc} + */ + @Override + default A foldRight(A a, Iterable as) { + return reduceRight(snoc(a, as)); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java index 3b7610510..402663d91 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java @@ -4,6 +4,10 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.monoid.Monoid; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Not.not; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find; + /** * A {@link Monoid} instance formed by Boolean. Equivalent to logical &&. * @@ -27,6 +31,11 @@ public Boolean apply(Boolean x, Boolean y) { return x && y; } + @Override + public Boolean reduceLeft(Iterable bools) { + return find(not(id()), bools).orElse(true); + } + @Override public boolean test(Boolean x, Boolean y) { return apply(x, y); diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java index a933c86a8..97028b692 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java @@ -5,6 +5,8 @@ import com.jnape.palatable.lambda.monoid.Monoid; import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.CatMaybes.catMaybes; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head; /** * A {@link Monoid} instance formed by {@link Maybe}<A>. The application to two {@link Maybe} values @@ -33,6 +35,11 @@ public Maybe apply(Maybe x, Maybe y) { return x.fmap(Maybe::just).orElse(y); } + @Override + public Maybe reduceLeft(Iterable> maybes) { + return head(catMaybes(maybes)); + } + @SuppressWarnings("unchecked") public static First first() { return INSTANCE; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java index e4bc56b8c..68d0813a8 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java @@ -4,6 +4,9 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.monoid.Monoid; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find; + /** * A {@link Monoid} instance formed by Boolean. Equivalent to logical ||. * @@ -32,6 +35,11 @@ public boolean test(Boolean x, Boolean y) { return apply(x, y); } + @Override + public Boolean reduceLeft(Iterable bools) { + return find(id(), bools).orElse(false); + } + @Override public Or flip() { return this; diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AndTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AndTest.java index 8ae51c840..d78aaf702 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AndTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AndTest.java @@ -2,6 +2,9 @@ import org.junit.Test; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.monoid.builtin.And.and; import static org.junit.Assert.assertEquals; @@ -20,4 +23,15 @@ public void monoid() { assertEquals(false, and.apply(true, false)); assertEquals(false, and.apply(false, false)); } + + @Test(timeout = 500) + public void shortCircuiting() { + Iterable bools = cons(false, repeat(true)); + And and = and(); + + assertEquals(false, and.foldLeft(false, bools)); + assertEquals(false, and.foldLeft(true, bools)); + assertEquals(false, and.reduceLeft(bools)); + assertEquals(false, and.foldMap(id(), bools)); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/FirstTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/FirstTest.java index 4851243ba..76675e52e 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/FirstTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/FirstTest.java @@ -1,9 +1,12 @@ package com.jnape.palatable.lambda.monoid.builtin; +import com.jnape.palatable.lambda.adt.Maybe; 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.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.monoid.builtin.First.first; import static org.junit.Assert.assertEquals; @@ -22,4 +25,15 @@ public void monoid() { assertEquals(just(2), first.apply(nothing(), just(2))); assertEquals(nothing(), first.apply(nothing(), nothing())); } + + @Test(timeout = 500) + public void shortCircuiting() { + Iterable> maybeInts = repeat(just(1)); + First first = First.first(); + + assertEquals(just(1), first.foldLeft(nothing(), maybeInts)); + assertEquals(just(1), first.foldLeft(just(1), maybeInts)); + assertEquals(just(1), first.reduceLeft(maybeInts)); + assertEquals(just(1), first.foldMap(id(), maybeInts)); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/OrTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/OrTest.java index 336a98e4d..d421c1e5d 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/OrTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/OrTest.java @@ -2,6 +2,9 @@ import org.junit.Test; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.monoid.builtin.Or.or; import static org.junit.Assert.assertEquals; @@ -20,4 +23,15 @@ public void monoid() { assertEquals(true, or.apply(false, true)); assertEquals(false, or.apply(false, false)); } + + @Test(timeout = 500) + public void shortCircuiting() { + Iterable bools = cons(true, repeat(false)); + Or or = or(); + + assertEquals(true, or.foldLeft(false, bools)); + assertEquals(true, or.foldLeft(true, bools)); + assertEquals(true, or.reduceLeft(bools)); + assertEquals(true, or.foldMap(id(), bools)); + } } \ No newline at end of file From 172c8d6abc0920cc57981f2498af33f7df01267c Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 May 2018 14:38:00 -0500 Subject: [PATCH 007/348] Housekeeping --- .../palatable/lambda/functions/builtin/fn2/GroupBy.java | 6 +++--- .../jnape/palatable/lambda/functions/builtin/fn2/Slide.java | 2 +- .../jnape/palatable/lambda/functions/builtin/fn3/Times.java | 2 +- .../jnape/palatable/lambda/iteration/ImmutableQueue.java | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java index 11dc659bc..e2ba773e5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java @@ -12,8 +12,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; /** - * Given an Iterable<V> vs and a key function V -> K f, fold - * vs into a Map<K, List<V>> by applying f to each element of + * Given an Iterable<V> vs and a key function V -> K f, + * fold vs into a Map<K, List<V>> by applying f to each element of * vs, retaining values that map to the same key in a list, in the order they were iterated in. * * @param the Map key type @@ -32,7 +32,7 @@ public Map> apply(Function keyFn, Iterable return foldLeft((m, v) -> { m.computeIfAbsent(keyFn.apply(v), __ -> new ArrayList<>()).add(v); return m; - }, new HashMap>(), vs); + }, new HashMap<>(), vs); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java index 69e1ec16e..337d59788 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java @@ -14,7 +14,7 @@ * Iterable} by one element at a time, returning an {@link Iterable}<{@link Iterable}<A>>. *

* Example: - *

+ * * slide(2, asList(1, 2, 3, 4, 5)); // [[1, 2], [2, 3], [3, 4], [4, 5]] * * @param the Iterable element type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java index 2227c584e..cdf33a8d7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java @@ -15,7 +15,7 @@ * n times, returning the result. *

* Example: - *

+ * * times(3, x -> x + 1, 0); // 3 * * @param the input and output type diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java b/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java index 94d94d0b0..5a734a88c 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java @@ -112,7 +112,7 @@ ImmutableQueue tail() { if (!outTail.isEmpty()) return new NonEmpty<>(outTail, inbound); - ImmutableStack newOutbound = foldLeft(ImmutableStack::push, ImmutableStack.empty(), inbound); + ImmutableStack newOutbound = foldLeft(ImmutableStack::push, ImmutableStack.empty(), inbound); return newOutbound.isEmpty() ? empty() : new NonEmpty<>(newOutbound, ImmutableStack.empty()); } } From 4e93dc76f28126136c41d4d5e90e916952ccd6eb Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 May 2018 14:41:20 -0500 Subject: [PATCH 008/348] Updating copyright in LICENSE and description in pom --- LICENSE | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 89c5bf75e..b35067105 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 palatable +Copyright (c) 2018 John Napier (jnape) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/pom.xml b/pom.xml index 75fbb10f8..ff6fc58e4 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ Lambda - Functional patterns for Java 8 + Functional patterns for Java http://www.github.com/palatable/lambda From 4f9304704a3d8e9cc2710f50cef9504ccc16fb16 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 May 2018 16:50:33 -0500 Subject: [PATCH 009/348] Adding ToArray for conveniently creating an A[] from Iterable --- CHANGELOG.md | 1 + .../lambda/functions/builtin/fn2/ToArray.java | 50 +++++++++++++++++++ .../functions/builtin/fn2/ToArrayTest.java | 50 +++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArrayTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b7f3c547..296107a18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `Upcast` for safely casting up a type hierarchy - `SetLens`, lenses operating on `Set`s +- `ToArray`, for converting `Iterable` to `A[]` ## [3.0.0] - 2018-05-04 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java new file mode 100644 index 000000000..e12ae85b1 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java @@ -0,0 +1,50 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; + +import java.lang.reflect.Array; +import java.util.Collection; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; + +/** + * Write all the elements of an {@link Iterable} directly into an array of the specified type. If the {@link Iterable} + * is an instance of {@link Collection}, use {@link Collection#toArray(Object[])}. + * + * @param the {@link Iterable} element type + */ +public final class ToArray implements Fn2, Iterable, A[]> { + + private static final ToArray INSTANCE = new ToArray<>(); + + private ToArray() { + } + + @Override + @SuppressWarnings("unchecked") + public A[] apply(Class arrayType, Iterable as) { + A[] array = (A[]) Array.newInstance(arrayType.getComponentType(), size(as).intValue()); + if (as instanceof Collection) + return ((Collection) as).toArray(array); + + int index = 0; + for (A a : as) { + array[index++] = a; + } + return array; + } + + @SuppressWarnings("unchecked") + public static ToArray toArray() { + return INSTANCE; + } + + public static Fn1, A[]> toArray(Class arrayType) { + return ToArray.toArray().apply(arrayType); + } + + public static A[] toArray(Class arrayType, Iterable as) { + return toArray(arrayType).apply(as); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArrayTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArrayTest.java new file mode 100644 index 000000000..0c4b3001e --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArrayTest.java @@ -0,0 +1,50 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import java.util.AbstractCollection; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.ToArray.toArray; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyIterator; +import static org.junit.Assert.assertArrayEquals; + +public class ToArrayTest { + + @Test + public void writesIterableToArray() { + assertArrayEquals(new Integer[]{1, 2, 3}, toArray(Integer[].class, asList(1, 2, 3))); + + List variance = asList(1, 2, 3); + assertArrayEquals(new Object[]{1, 2, 3}, toArray(Object[].class, variance)); + } + + @Test + public void usesCollectionToArrayIfPossible() { + Object sentinel = new Object(); + class CustomCollection extends AbstractCollection { + @Override + public Iterator iterator() { + return emptyIterator(); + } + + @Override + public int size() { + return 0; + } + + @Override + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + T[] result = Arrays.copyOf(a, 1); + result[0] = (T) sentinel; + return result; + } + } + + assertArrayEquals(new Object[]{sentinel}, toArray(Object[].class, new CustomCollection())); + } +} \ No newline at end of file From fa6261ea51fddbd5f190417d7c9a239531d87794 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 May 2018 16:58:55 -0500 Subject: [PATCH 010/348] Adding more javadocs to MapLens --- .../jnape/palatable/lambda/lens/lenses/MapLens.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java index f412c1161..6da58926e 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java @@ -128,6 +128,9 @@ public static Lens.Simple, Collection> values() { /** * A lens that focuses on the inverse of a map (keys and values swapped). In the case of multiple equal values * becoming keys, the last one wins. + *

+ * Note that this lens is very likely to NOT be lawful, since "you get back what you put in" will fail for any keys + * that map to the same value. * * @param the key type * @param the value type @@ -149,9 +152,11 @@ public static Lens.Simple, Map> inverted() { /** * A lens that focuses on a map while mapping its values with the mapping function. *

- * Note that this lens is NOT lawful, since "you get back what you put in" fails for all values B that - * do not map from the current values in S (new mappings cannot be preserved as the inversion of - * fn is not known). + * Note that this lens is very likely to NOT be lawful, since "you get back what you put in" will fail for all + * values B that do not map from the current values in S (new mappings cannot be + * preserved as the inversion of fn is not known). Furthermore, if fn is injective + * (multiple Vs map to the same V2), this lens will also not be lawful for similar reasons + * as stated above. * * @param fn the mapping function * @param the key type @@ -183,7 +188,7 @@ public static Lens.Simple, Map> mappingValues(Functi * @param iso the mapping {@link Iso} * @param the key type * @param the unfocused map value type - * @param the focused map value types + * @param the focused map value type * @return a lens that focuses on a map while mapping its values */ public static Lens.Simple, Map> mappingValues(Iso iso) { From 456092763c87e0b898bc8373f4f775c2f9217e3e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 May 2018 17:18:26 -0500 Subject: [PATCH 011/348] [maven-release-plugin] prepare release lambda-3.0.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ff6fc58e4..21483d5fe 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.0.1-SNAPSHOT + 3.0.1 jar Lambda From a4836ee4549333cf06e65f2d6ac7a1656f5e7496 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 May 2018 17:18:31 -0500 Subject: [PATCH 012/348] [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 21483d5fe..80c0cc201 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.0.1 + 3.0.2-SNAPSHOT jar Lambda From 900e6116d0b45e150717be94edd6a5d9c2ddddeb Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 May 2018 17:23:44 -0500 Subject: [PATCH 013/348] Updating CHANGELOG and README to reflect latest version --- CHANGELOG.md | 5 ++++- README.md | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 296107a18..784914c1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +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] + +## [3.0.1] - 2018-05-13 ### Changed - `ToMap` accepts an `Iterable` covariant in `Map.Entry` - `RecursiveResult#invert` is also a `RecursiveResult` @@ -312,7 +314,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.0...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-3.0.1...HEAD +[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 [2.1.0]: https://github.com/palatable/lambda/compare/lambda-2.0.0...lambda-2.1.0 diff --git a/README.md b/README.md index 5d8eff2e7..a08d8dcc8 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 3.0.0 + 3.0.1 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '3.0.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '3.0.1' ``` Examples From 1a99c5e10f8a94e0d5fae54c07a21992d57590f2 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 18 May 2018 18:28:28 -0500 Subject: [PATCH 014/348] Default implementation for TypeSafeKey.Simple#apply --- CHANGELOG.md | 2 ++ .../palatable/lambda/adt/hmap/TypeSafeKey.java | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 784914c1d..34a28176b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +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] +### Changed +- `TypeSafeKey.Simple` now has a default `#apply` implementation ## [3.0.1] - 2018-05-13 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java index a71e4c04c..95ebf03d7 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java @@ -87,12 +87,6 @@ public boolean equals(Object obj) { */ static Simple typeSafeKey() { return new TypeSafeKey.Simple() { - @Override - @SuppressWarnings("unchecked") - public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { - return (PSFT) pafb; - } }; } @@ -102,5 +96,12 @@ public

, FT ex * @param The type of the value that this key maps to inside an {@link HMap} */ interface Simple extends TypeSafeKey { + + @Override + @SuppressWarnings("unchecked") + default

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { + return (PSFT) pafb; + } } } \ No newline at end of file From 629000a14976b6436845e3becf7b008a18bba845 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 18 May 2018 18:44:37 -0500 Subject: [PATCH 015/348] IterableLens#mapping, an Iso for mapping Iterables --- CHANGELOG.md | 3 +++ .../lambda/lens/lenses/IterableLens.java | 16 ++++++++++++++++ .../lambda/lens/lenses/IterableLensTest.java | 17 +++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34a28176b..b31e49a66 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 +- `IterableLens#mapping`, an `Iso` that maps values + ### Changed - `TypeSafeKey.Simple` now has a default `#apply` implementation diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java index 0c765505d..cccf68730 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java @@ -3,12 +3,16 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.builtin.fn1.Head; import com.jnape.palatable.lambda.functions.builtin.fn1.Tail; +import com.jnape.palatable.lambda.lens.Iso; import com.jnape.palatable.lambda.lens.Lens; import static com.jnape.palatable.lambda.functions.Fn2.fn2; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; +import static com.jnape.palatable.lambda.lens.Iso.simpleIso; import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.lens.functions.View.view; /** * Lenses that operate on {@link Iterable}s. @@ -43,4 +47,16 @@ public static Lens.Simple, Maybe> head() { public static Lens.Simple, Iterable> tail() { return simpleLens(Tail::tail, fn2(Head.head().andThen(o -> o.fmap(cons()).orElse(id()))).toBiFunction()); } + + /** + * An iso focusing on the mapped values of an {@link Iterable}. + * + * @param abIso the iso from A to B + * @param the unmapped {@link Iterable} element type + * @param the mapped {@link Iterable} element type + * @return an iso that maps {@link Iterable}<A> to {@link Iterable}<B> + */ + public static Iso.Simple, Iterable> mapping(Iso abIso) { + return simpleIso(map(view(abIso)), map(view(abIso.mirror()))); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java b/src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java index ff5e30327..561bc4d99 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java @@ -1,12 +1,14 @@ package com.jnape.palatable.lambda.lens.lenses; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.lens.Iso; import com.jnape.palatable.lambda.lens.Lens; 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.functions.builtin.fn2.Map.map; +import static com.jnape.palatable.lambda.lens.Iso.simpleIso; import static com.jnape.palatable.lambda.lens.functions.Over.over; import static com.jnape.palatable.lambda.lens.functions.Set.set; import static com.jnape.palatable.lambda.lens.functions.View.view; @@ -51,4 +53,19 @@ public void tail() { assertThat(over(tail, map(x -> x + 1), emptyList()), isEmpty()); assertThat(over(tail, map(x -> x + 1), asList(1, 2, 3)), iterates(1, 3, 4)); } + + @Test + public void mapping() { + Iso.Simple, Iterable> iso = IterableLens.mapping(simpleIso(Integer::parseInt, Object::toString)); + + assertThat(view(iso, emptyList()), isEmpty()); + assertThat(view(iso, singletonList("1")), iterates(1)); + assertThat(view(iso, asList("1", "2", "3")), iterates(1, 2, 3)); + + assertThat(set(iso, emptyList(), emptyList()), isEmpty()); + assertThat(set(iso, singletonList(1), emptyList()), iterates("1")); + assertThat(set(iso, singletonList(2), singletonList("1")), iterates("2")); + assertThat(set(iso, asList(1, 2, 3), singletonList("1")), iterates("1", "2", "3")); + assertThat(set(iso, emptyList(), singletonList("1")), isEmpty()); + } } \ No newline at end of file From c59101954a5d58b65a72bb0e0d21035c558ef722 Mon Sep 17 00:00:00 2001 From: George Shakhnazaryan Date: Fri, 18 May 2018 20:21:59 -0500 Subject: [PATCH 016/348] Make `singletonHMap` store the A instead of the B of TypeSafeKey. Previously, HMap equality was broken for `singletonHMap` with custom keys. --- .../jnape/palatable/lambda/adt/hmap/HMap.java | 2 +- .../adt/hmap/CustomTypeSafeKeyTest.java | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/jnape/palatable/lambda/adt/hmap/CustomTypeSafeKeyTest.java 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 83fc47f11..e2e3fd3c1 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 @@ -196,7 +196,7 @@ public static HMap emptyHMap() { * @return a singleton HMap */ public static HMap singletonHMap(TypeSafeKey key, V value) { - return new HMap(singletonMap(key, value)); + return emptyHMap().put(key, value); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/CustomTypeSafeKeyTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/CustomTypeSafeKeyTest.java new file mode 100644 index 000000000..9531a72c2 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/CustomTypeSafeKeyTest.java @@ -0,0 +1,87 @@ +package com.jnape.palatable.lambda.adt.hmap; + +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.lens.Iso; +import org.junit.Test; + +import java.math.BigInteger; +import java.util.Objects; + +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.hmap.CustomTypeSafeKeyTest.CustomTypeSafeKey.customKey; +import static com.jnape.palatable.lambda.adt.hmap.HMap.emptyHMap; +import static com.jnape.palatable.lambda.adt.hmap.HMap.singletonHMap; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static java.math.BigInteger.ONE; +import static org.junit.Assert.assertEquals; + +public class CustomTypeSafeKeyTest { + + public static class CustomTypeSafeKey implements TypeSafeKey { + int tag; + Iso.Simple iso; + + private CustomTypeSafeKey(int tag, Iso.Simple iso) { + this.tag = tag; + this.iso = iso; + } + + @Override + public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return iso.apply(pafb); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CustomTypeSafeKey customTypeSafeKey = (CustomTypeSafeKey) o; + return Objects.equals(tag, customTypeSafeKey.tag); + } + + @Override + public int hashCode() { + return Objects.hash(tag); + } + + static CustomTypeSafeKey customKey(int tag, Iso.Simple iso) { + return new CustomTypeSafeKey<>(tag, iso); + } + + static CustomTypeSafeKey customKey(int tag) { + return customKey(tag, Iso.simpleIso(id(), id())); + } + } + + private static final Iso.Simple STRING_TO_LONG = Iso.simpleIso(Long::parseLong, String::valueOf); + private static final Iso.Simple LONG_TO_BIG_INTEGER = Iso.simpleIso(BigInteger::valueOf, BigInteger::longValue); + + private static final CustomTypeSafeKey KEY_1_AS_STRING = CustomTypeSafeKey.customKey(1); + private static final CustomTypeSafeKey KEY_1_AS_STRING_AGAIN = CustomTypeSafeKey.customKey(1); + private static final CustomTypeSafeKey KEY_1_AS_LONG = customKey(1, STRING_TO_LONG); + private static final CustomTypeSafeKey KEY_1_AS_BIG_INTEGER = customKey(1, STRING_TO_LONG.andThen(LONG_TO_BIG_INTEGER)); + + @Test + public void getDifferentViewsOfSameKey() { + HMap hMap = singletonHMap(KEY_1_AS_STRING, "1"); + assertEquals(just("1"), hMap.get(KEY_1_AS_STRING)); + assertEquals(just("1"), hMap.get(KEY_1_AS_STRING_AGAIN)); + assertEquals(just(1L), hMap.get(KEY_1_AS_LONG)); + assertEquals(just(ONE), hMap.get(KEY_1_AS_BIG_INTEGER)); + assertEquals(nothing(), hMap.get(customKey(2))); + } + + @Test + public void putStoresA() { + assertEquals(emptyHMap().put(KEY_1_AS_STRING, "1"), emptyHMap().put(KEY_1_AS_LONG, 1L)); + assertEquals(emptyHMap().put(KEY_1_AS_STRING, "1"), emptyHMap().put(KEY_1_AS_BIG_INTEGER, ONE)); + } + + @Test + public void singletonHMapStoresA() { + assertEquals(singletonHMap(KEY_1_AS_STRING, "1"), singletonHMap(KEY_1_AS_LONG, 1L)); + assertEquals(singletonHMap(KEY_1_AS_STRING, "1"), singletonHMap(KEY_1_AS_BIG_INTEGER, ONE)); + } +} From 5c118f11b028315035043e0dd197b5244f745687 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 20 May 2018 16:21:36 -0500 Subject: [PATCH 017/348] Mapped TSKs can put initial values and the original key can fetch them --- CHANGELOG.md | 3 + .../lambda/adt/hmap/TypeSafeKey.java | 6 ++ .../adt/hmap/CustomTypeSafeKeyTest.java | 87 ------------------- .../palatable/lambda/adt/hmap/HMapTest.java | 25 ++++++ .../lambda/adt/hmap/TypeSafeKeyTest.java | 26 ++++++ 5 files changed, 60 insertions(+), 87 deletions(-) delete mode 100644 src/test/java/com/jnape/palatable/lambda/adt/hmap/CustomTypeSafeKeyTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index b31e49a66..259a826cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - `TypeSafeKey.Simple` now has a default `#apply` implementation +### Fixed +- mapped `TypeSafeKey` instances can be used for initial put in an `HMap`, and the base key can be used to retrieve them + ## [3.0.1] - 2018-05-13 ### Changed - `ToMap` accepts an `Iterable` covariant in `Map.Entry` diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java index 95ebf03d7..8bae70949 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java @@ -6,6 +6,8 @@ import com.jnape.palatable.lambda.lens.Iso; import com.jnape.palatable.lambda.lens.LensLike; +import java.util.Objects; + /** * An interface representing a parametrized key for use in {@link HMap}s. Additionally, every {@link TypeSafeKey} is an * {@link Iso} from the type the value is stored as to the type it's viewed and set as (on the way in / on the way out). @@ -87,6 +89,10 @@ public boolean equals(Object obj) { */ static Simple typeSafeKey() { return new TypeSafeKey.Simple() { + @Override + public boolean equals(Object obj) { + return obj instanceof Simple ? this == obj : Objects.equals(obj, this); + } }; } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/CustomTypeSafeKeyTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/CustomTypeSafeKeyTest.java deleted file mode 100644 index 9531a72c2..000000000 --- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/CustomTypeSafeKeyTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.jnape.palatable.lambda.adt.hmap; - -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.lens.Iso; -import org.junit.Test; - -import java.math.BigInteger; -import java.util.Objects; - -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.hmap.CustomTypeSafeKeyTest.CustomTypeSafeKey.customKey; -import static com.jnape.palatable.lambda.adt.hmap.HMap.emptyHMap; -import static com.jnape.palatable.lambda.adt.hmap.HMap.singletonHMap; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static java.math.BigInteger.ONE; -import static org.junit.Assert.assertEquals; - -public class CustomTypeSafeKeyTest { - - public static class CustomTypeSafeKey implements TypeSafeKey { - int tag; - Iso.Simple iso; - - private CustomTypeSafeKey(int tag, Iso.Simple iso) { - this.tag = tag; - this.iso = iso; - } - - @Override - public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply(PAFB pafb) { - return iso.apply(pafb); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - CustomTypeSafeKey customTypeSafeKey = (CustomTypeSafeKey) o; - return Objects.equals(tag, customTypeSafeKey.tag); - } - - @Override - public int hashCode() { - return Objects.hash(tag); - } - - static CustomTypeSafeKey customKey(int tag, Iso.Simple iso) { - return new CustomTypeSafeKey<>(tag, iso); - } - - static CustomTypeSafeKey customKey(int tag) { - return customKey(tag, Iso.simpleIso(id(), id())); - } - } - - private static final Iso.Simple STRING_TO_LONG = Iso.simpleIso(Long::parseLong, String::valueOf); - private static final Iso.Simple LONG_TO_BIG_INTEGER = Iso.simpleIso(BigInteger::valueOf, BigInteger::longValue); - - private static final CustomTypeSafeKey KEY_1_AS_STRING = CustomTypeSafeKey.customKey(1); - private static final CustomTypeSafeKey KEY_1_AS_STRING_AGAIN = CustomTypeSafeKey.customKey(1); - private static final CustomTypeSafeKey KEY_1_AS_LONG = customKey(1, STRING_TO_LONG); - private static final CustomTypeSafeKey KEY_1_AS_BIG_INTEGER = customKey(1, STRING_TO_LONG.andThen(LONG_TO_BIG_INTEGER)); - - @Test - public void getDifferentViewsOfSameKey() { - HMap hMap = singletonHMap(KEY_1_AS_STRING, "1"); - assertEquals(just("1"), hMap.get(KEY_1_AS_STRING)); - assertEquals(just("1"), hMap.get(KEY_1_AS_STRING_AGAIN)); - assertEquals(just(1L), hMap.get(KEY_1_AS_LONG)); - assertEquals(just(ONE), hMap.get(KEY_1_AS_BIG_INTEGER)); - assertEquals(nothing(), hMap.get(customKey(2))); - } - - @Test - public void putStoresA() { - assertEquals(emptyHMap().put(KEY_1_AS_STRING, "1"), emptyHMap().put(KEY_1_AS_LONG, 1L)); - assertEquals(emptyHMap().put(KEY_1_AS_STRING, "1"), emptyHMap().put(KEY_1_AS_BIG_INTEGER, ONE)); - } - - @Test - public void singletonHMapStoresA() { - assertEquals(singletonHMap(KEY_1_AS_STRING, "1"), singletonHMap(KEY_1_AS_LONG, 1L)); - assertEquals(singletonHMap(KEY_1_AS_STRING, "1"), singletonHMap(KEY_1_AS_BIG_INTEGER, ONE)); - } -} 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 8495b059f..65db8ee50 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 @@ -2,6 +2,7 @@ import org.junit.Test; +import java.math.BigInteger; import java.util.HashMap; import java.util.NoSuchElementException; @@ -12,6 +13,8 @@ import static com.jnape.palatable.lambda.adt.hmap.HMap.hMap; import static com.jnape.palatable.lambda.adt.hmap.HMap.singletonHMap; import static com.jnape.palatable.lambda.adt.hmap.TypeSafeKey.typeSafeKey; +import static com.jnape.palatable.lambda.lens.Iso.simpleIso; +import static java.math.BigInteger.ONE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -36,6 +39,28 @@ public void getForAbsentKey() { .get(typeSafeKey())); } + @Test + public void storesTypeSafeKeyBaseValue() { + TypeSafeKey.Simple stringKey = typeSafeKey(); + TypeSafeKey longKey = stringKey.andThen(simpleIso(Long::parseLong, String::valueOf)); + TypeSafeKey bigIntegerKey = longKey.andThen(simpleIso(BigInteger::valueOf, BigInteger::longValue)); + + HMap hMap = singletonHMap(stringKey, "1"); + assertEquals(just("1"), hMap.get(stringKey)); + assertEquals(just(1L), hMap.get(longKey)); + assertEquals(just(ONE), hMap.get(bigIntegerKey)); + + assertNotEquals(typeSafeKey(), typeSafeKey()); + + assertEquals(emptyHMap().put(longKey, 1L).get(longKey), emptyHMap().put(stringKey, "1").get(longKey)); + assertEquals(emptyHMap().put(stringKey, "1").get(stringKey), emptyHMap().put(longKey, 1L).get(stringKey)); + assertEquals(emptyHMap().put(stringKey, "1").get(stringKey), emptyHMap().put(bigIntegerKey, ONE).get(stringKey)); + + assertEquals(singletonHMap(stringKey, "1"), singletonHMap(longKey, 1L)); + assertEquals(singletonHMap(stringKey, "1"), singletonHMap(bigIntegerKey, ONE)); + assertEquals(singletonHMap(longKey, 1L), singletonHMap(bigIntegerKey, ONE)); + } + @Test public void getForPresentKeyWithNullValue() { TypeSafeKey stringKey = typeSafeKey(); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java index 577902c8c..b9bb7e802 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java @@ -9,6 +9,7 @@ import static com.jnape.palatable.lambda.lens.Iso.simpleIso; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static testsupport.assertion.LensAssert.assertLensLawfulness; @@ -45,4 +46,29 @@ public void discardRPreservesTypeSafeKey() { assertEquals(just("123"), map.get(discardedKey)); } + + @Test + public void defaultEquality() { + TypeSafeKey.Simple keyA = typeSafeKey(); + TypeSafeKey mappedKeyA = keyA.andThen(simpleIso(id(), id())); + + assertEquals(keyA, keyA); + assertEquals(keyA, mappedKeyA); + assertEquals(mappedKeyA, keyA); + assertEquals(keyA.hashCode(), mappedKeyA.hashCode()); + + TypeSafeKey.Simple keyB = typeSafeKey(); + assertNotEquals(keyA, keyB); + assertNotEquals(keyB, keyA); + assertNotEquals(keyB, mappedKeyA); + assertNotEquals(mappedKeyA, keyB); + + TypeSafeKey differentMappedKeyA = keyA.andThen(simpleIso(id(), id())); + assertEquals(keyA, differentMappedKeyA); + assertEquals(differentMappedKeyA, keyA); + assertEquals(mappedKeyA, differentMappedKeyA); + assertEquals(differentMappedKeyA, mappedKeyA); + assertEquals(keyA.hashCode(), differentMappedKeyA.hashCode()); + assertEquals(mappedKeyA.hashCode(), differentMappedKeyA.hashCode()); + } } \ No newline at end of file From 0e0ceb2dd1880f4103472f3c168172acb72a5cf9 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 20 May 2018 16:24:48 -0500 Subject: [PATCH 018/348] Updating CHANGELOG reflecting @gshakh's pull request --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 259a826cc..c61bcb6c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Fixed - mapped `TypeSafeKey` instances can be used for initial put in an `HMap`, and the base key can be used to retrieve them +- Merged pull request fixing issue storing values at mapped `TypeSafeKey` in `singletonHMap` ## [3.0.1] - 2018-05-13 ### Changed From 3776cfbd7751160569cc8aa0e67ffb96212c72b8 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 21 May 2018 01:43:17 -0500 Subject: [PATCH 019/348] [maven-release-plugin] prepare release lambda-3.0.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 80c0cc201..ac48a3a91 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.0.2-SNAPSHOT + 3.0.2 jar Lambda From de3e1a4a85e23d0c4b13c2ab0aaf85471dfec1d6 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 21 May 2018 01:43:23 -0500 Subject: [PATCH 020/348] [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 021/348] 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 022/348] 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 023/348] 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 024/348] 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 025/348] 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 026/348] 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 027/348] [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 From 8eb22317e4fd39811c2d82243e4c759dd6a2c985 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 27 May 2018 17:38:14 -0500 Subject: [PATCH 028/348] [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 3f4928797..a993aac9b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.0.3 + 3.0.4-SNAPSHOT jar Lambda From fb1f91a4ca89c69f7a49b43cdbcd2912c7e3422b Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 3 Jun 2018 15:40:27 -0500 Subject: [PATCH 029/348] Updating CHANGELOG and README to reflect latest version --- CHANGELOG.md | 5 ++++- README.md | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98efd8a2e..f4d7c4b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +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] + +## [3.0.3] - 2018-05-27 ### Added - `Lens#toIso`, for converting a lens to an iso - `HMap#hMap` overloads up to 8 bindings deep @@ -332,7 +334,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.2...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-3.0.3...HEAD +[3.0.3]: https://github.com/palatable/lambda/compare/lambda-3.0.2...lambda-3.0.3 [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 diff --git a/README.md b/README.md index 1d889d106..13892496a 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 3.0.2 + 3.0.3 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '3.0.2' +compile group: 'com.jnape.palatable', name: 'lambda', version: '3.0.3' ``` Examples From b4ee3b8361619533a7f95530eaf12fff2229e103 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 3 Jun 2018 15:33:59 -0500 Subject: [PATCH 030/348] Adding static factory overloads for Fn3-8 to aid lambda coercing --- CHANGELOG.md | 2 ++ .../jnape/palatable/lambda/functions/Fn3.java | 14 ++++++++++++++ .../jnape/palatable/lambda/functions/Fn4.java | 15 +++++++++++++++ .../jnape/palatable/lambda/functions/Fn5.java | 16 ++++++++++++++++ .../jnape/palatable/lambda/functions/Fn6.java | 17 +++++++++++++++++ .../jnape/palatable/lambda/functions/Fn7.java | 18 ++++++++++++++++++ .../jnape/palatable/lambda/functions/Fn8.java | 19 +++++++++++++++++++ .../palatable/lambda/functions/Fn3Test.java | 9 ++++++--- .../palatable/lambda/functions/Fn4Test.java | 11 +++++++---- .../palatable/lambda/functions/Fn5Test.java | 13 ++++++++----- .../palatable/lambda/functions/Fn6Test.java | 4 +++- .../palatable/lambda/functions/Fn7Test.java | 4 +++- .../palatable/lambda/functions/Fn8Test.java | 19 +++++++++++-------- 13 files changed, 139 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4d7c4b39..ef274c415 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +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] +### Added +- `Fn3-8` static factory overloads to aid in coercing lambdas ## [3.0.3] - 2018-05-27 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java index 34d725aed..c0d073acd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java @@ -126,4 +126,18 @@ static Fn3 fn3(Fn1> curriedFn1) { static Fn3 fn3(Fn2> curriedFn2) { return (a, b, c) -> curriedFn2.apply(a, b).apply(c); } + + /** + * Static factory method for coercing a lambda to an {@link Fn3}; + * + * @param fn the lambda to coerce + * @param the first input argument type + * @param the second input argument type + * @param the third input argument type + * @param the output type + * @return the {@link Fn3} + */ + static Fn3 fn3(Fn3 fn) { + return fn; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java index e98bb9da9..6e71576c4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java @@ -158,4 +158,19 @@ static Fn4 fn4(Fn2> curriedFn2 static Fn4 fn4(Fn3> curriedFn3) { return (a, b, c, d) -> curriedFn3.apply(a, b, c).apply(d); } + + /** + * Static factory method for coercing a lambda to an {@link Fn4}; + * + * @param fn the lambda to coerce + * @param the first input argument type + * @param the second input argument type + * @param the third input argument type + * @param the fourth input argument type + * @param the output type + * @return the {@link Fn4} + */ + static Fn4 fn4(Fn4 fn) { + return fn; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java index 7e8b5abdf..9c8b3affd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java @@ -193,4 +193,20 @@ static Fn5 fn5(Fn3> c static Fn5 fn5(Fn4> curriedFn4) { return (a, b, c, d, e) -> curriedFn4.apply(a, b, c, d).apply(e); } + + /** + * Static factory method for coercing a lambda to an {@link Fn5}; + * + * @param fn the lambda to coerce + * @param the first input argument type + * @param the second input argument type + * @param the third input argument type + * @param the fourth input argument type + * @param the fifth input argument type + * @param the output type + * @return the {@link Fn5} + */ + static Fn5 fn5(Fn5 fn) { + return fn; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java index e81331b16..5f55113cf 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java @@ -231,4 +231,21 @@ static Fn6 fn6(Fn4 Fn6 fn6(Fn5> curriedFn5) { return (a, b, c, d, e, f) -> curriedFn5.apply(a, b, c, d, e).apply(f); } + + /** + * Static factory method for coercing a lambda to an {@link Fn6}; + * + * @param fn the lambda to coerce + * @param the first input argument type + * @param the second input argument type + * @param the third input argument type + * @param the fourth input argument type + * @param the fifth input argument type + * @param the sixth input argument type + * @param the output type + * @return the {@link Fn6} + */ + static Fn6 fn6(Fn6 fn) { + return fn; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index 20ad5d8e5..9ffe47762 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -272,4 +272,22 @@ static Fn7 fn7(Fn5 Fn7 fn7(Fn6> curriedFn6) { return (a, b, c, d, e, f, g) -> curriedFn6.apply(a, b, c, d, e, f).apply(g); } + + /** + * Static factory method for coercing a lambda to an {@link Fn7}; + * + * @param fn the lambda to coerce + * @param the first input argument type + * @param the second input argument type + * @param the third input argument type + * @param the fourth input argument type + * @param the fifth input argument type + * @param the sixth input argument type + * @param the seventh input argument type + * @param the output type + * @return the {@link Fn7} + */ + static Fn7 fn7(Fn7 fn) { + return fn; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java index 6f80beb9f..f10f1aaf9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java @@ -322,4 +322,23 @@ static Fn8 fn8( Fn7> curriedFn7) { return (a, b, c, d, e, f, g, h) -> curriedFn7.apply(a, b, c, d, e, f, g).apply(h); } + + /** + * Static factory method for coercing a lambda to an {@link Fn8}; + * + * @param fn the lambda to coerce + * @param the first input argument type + * @param the second input argument type + * @param the third input argument type + * @param the fourth input argument type + * @param the fifth input argument type + * @param the sixth input argument type + * @param the seventh input argument type + * @param the eighth input argument type + * @param the output type + * @return the {@link Fn8} + */ + static Fn8 fn8(Fn8 fn) { + return fn; + } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn3Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn3Test.java index 31f00e249..78ec9a225 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn3Test.java @@ -3,6 +3,7 @@ import org.junit.Test; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn3.fn3; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -31,11 +32,13 @@ public void uncurries() { } @Test - public void fn3() { + public void staticFactoryMethods() { Fn1> fn1 = a -> (b, c) -> a + b + c; - assertEquals("abc", Fn3.fn3(fn1).apply("a", "b", "c")); + assertEquals("abc", fn3(fn1).apply("a", "b", "c")); Fn2> fn2 = (a, b) -> c -> a + b + c; - assertEquals("abc", Fn3.fn3(fn2).apply("a", "b", "c")); + assertEquals("abc", fn3(fn2).apply("a", "b", "c")); + + assertEquals("abc", Fn3.fn3((a, b, c) -> a + b + c).apply("a", "b", "c")); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn4Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn4Test.java index f241fc88a..5808dac74 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn4Test.java @@ -3,6 +3,7 @@ import org.junit.Test; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn4.fn4; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -31,14 +32,16 @@ public void uncurries() { } @Test - public void fn4() { + public void staticFactoryMethods() { Fn1> fn1 = a -> (b, c, d) -> a + b + c + d; - assertEquals("abcd", Fn4.fn4(fn1).apply("a", "b", "c", "d")); + assertEquals("abcd", fn4(fn1).apply("a", "b", "c", "d")); Fn2> fn2 = (a, b) -> (c, d) -> a + b + c + d; - assertEquals("abcd", Fn4.fn4(fn2).apply("a", "b", "c", "d")); + assertEquals("abcd", fn4(fn2).apply("a", "b", "c", "d")); Fn3> fn3 = (a, b, c) -> (d) -> a + b + c + d; - assertEquals("abcd", Fn4.fn4(fn3).apply("a", "b", "c", "d")); + assertEquals("abcd", fn4(fn3).apply("a", "b", "c", "d")); + + assertEquals("abcd", Fn4.fn4((a, b, c, d) -> a + b + c + d).apply("a", "b", "c", "d")); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn5Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn5Test.java index bb5d2021d..f7f8097b8 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn5Test.java @@ -3,6 +3,7 @@ import org.junit.Test; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn5.fn5; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -32,17 +33,19 @@ public void uncurries() { } @Test - public void fn5() { + public void staticFactoryMethods() { Fn1> fn1 = a -> (b, c, d, e) -> a + b + c + d + e; - assertEquals("abcde", Fn5.fn5(fn1).apply("a", "b", "c", "d", "e")); + assertEquals("abcde", fn5(fn1).apply("a", "b", "c", "d", "e")); Fn2> fn2 = (a, b) -> (c, d, e) -> a + b + c + d + e; - assertEquals("abcde", Fn5.fn5(fn2).apply("a", "b", "c", "d", "e")); + assertEquals("abcde", fn5(fn2).apply("a", "b", "c", "d", "e")); Fn3> fn3 = (a, b, c) -> (d, e) -> a + b + c + d + e; - assertEquals("abcde", Fn5.fn5(fn3).apply("a", "b", "c", "d", "e")); + assertEquals("abcde", fn5(fn3).apply("a", "b", "c", "d", "e")); Fn4> fn4 = (a, b, c, d) -> (e) -> a + b + c + d + e; - assertEquals("abcde", Fn5.fn5(fn4).apply("a", "b", "c", "d", "e")); + assertEquals("abcde", fn5(fn4).apply("a", "b", "c", "d", "e")); + + assertEquals("abcde", Fn5.fn5((a, b, c, d, e) -> a + b + c + d + e).apply("a", "b", "c", "d", "e")); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn6Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn6Test.java index e52b1b54f..2f9faaa2d 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn6Test.java @@ -33,7 +33,7 @@ public void uncurries() { } @Test - public void fn6() { + public void staticFactoryMethods() { Fn1> fn1 = a -> (b, c, d, e, f) -> a + b + c + d + e + f; assertEquals("abcdef", Fn6.fn6(fn1).apply("a", "b", "c", "d", "e", "f")); @@ -48,5 +48,7 @@ public void fn6() { Fn5> fn5 = (a, b, c, d, e) -> (f) -> a + b + c + d + e + f; assertEquals("abcdef", Fn6.fn6(fn5).apply("a", "b", "c", "d", "e", "f")); + + assertEquals("abcdef", Fn6.fn6((a, b, c, d, e, f) -> a + b + c + d + e + f).apply("a", "b", "c", "d", "e", "f")); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn7Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn7Test.java index 9baf0fe0b..ed361c26c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn7Test.java @@ -34,7 +34,7 @@ public void uncurries() { } @Test - public void fn7() { + public void staticFactoryMethod() { Fn1> fn1 = a -> (b, c, d, e, f, g) -> a + b + c + d + e + f + g; assertEquals("abcdefg", Fn7.fn7(fn1).apply("a", "b", "c", "d", "e", "f", "g")); @@ -52,5 +52,7 @@ public void fn7() { Fn6> fn6 = (a, b, c, d, e, f) -> (g) -> a + b + c + d + e + f + g; assertEquals("abcdefg", Fn7.fn7(fn6).apply("a", "b", "c", "d", "e", "f", "g")); + + assertEquals("abcdefg", Fn7.fn7((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g).apply("a", "b", "c", "d", "e", "f", "g")); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn8Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn8Test.java index ea220e2f8..058168eb1 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn8Test.java @@ -3,6 +3,7 @@ import org.junit.Test; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn8.fn8; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -35,26 +36,28 @@ public void uncurries() { } @Test - public void fn8() { + public void staticFactoryMethods() { Fn1> fn1 = a -> (b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h; - assertEquals("abcdefgh", Fn8.fn8(fn1).apply("a", "b", "c", "d", "e", "f", "g", "h")); + assertEquals("abcdefgh", fn8(fn1).apply("a", "b", "c", "d", "e", "f", "g", "h")); Fn2> fn2 = (a, b) -> (c, d, e, f, g, h) -> a + b + c + d + e + f + g + h; - assertEquals("abcdefgh", Fn8.fn8(fn2).apply("a", "b", "c", "d", "e", "f", "g", "h")); + assertEquals("abcdefgh", fn8(fn2).apply("a", "b", "c", "d", "e", "f", "g", "h")); Fn3> fn3 = (a, b, c) -> (d, e, f, g, h) -> a + b + c + d + e + f + g + h; - assertEquals("abcdefgh", Fn8.fn8(fn3).apply("a", "b", "c", "d", "e", "f", "g", "h")); + assertEquals("abcdefgh", fn8(fn3).apply("a", "b", "c", "d", "e", "f", "g", "h")); Fn4> fn4 = (a, b, c, d) -> (e, f, g, h) -> a + b + c + d + e + f + g + h; - assertEquals("abcdefgh", Fn8.fn8(fn4).apply("a", "b", "c", "d", "e", "f", "g", "h")); + assertEquals("abcdefgh", fn8(fn4).apply("a", "b", "c", "d", "e", "f", "g", "h")); Fn5> fn5 = (a, b, c, d, e) -> (f, g, h) -> a + b + c + d + e + f + g + h; - assertEquals("abcdefgh", Fn8.fn8(fn5).apply("a", "b", "c", "d", "e", "f", "g", "h")); + assertEquals("abcdefgh", fn8(fn5).apply("a", "b", "c", "d", "e", "f", "g", "h")); Fn6> fn6 = (a, b, c, d, e, f) -> (g, h) -> a + b + c + d + e + f + g + h; - assertEquals("abcdefgh", Fn8.fn8(fn6).apply("a", "b", "c", "d", "e", "f", "g", "h")); + assertEquals("abcdefgh", fn8(fn6).apply("a", "b", "c", "d", "e", "f", "g", "h")); Fn7> fn7 = (a, b, c, d, e, f, g) -> (h) -> a + b + c + d + e + f + g + h; - assertEquals("abcdefgh", Fn8.fn8(fn7).apply("a", "b", "c", "d", "e", "f", "g", "h")); + assertEquals("abcdefgh", fn8(fn7).apply("a", "b", "c", "d", "e", "f", "g", "h")); + + assertEquals("abcdefgh", Fn8.fn8((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h).apply("a", "b", "c", "d", "e", "f", "g", "h")); } } From f0cbbb5a77eb2c38eda8a6cfc40eb747c383bd1b Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 3 Jun 2018 17:36:35 -0500 Subject: [PATCH 031/348] Adding composition guarantees to LensLike --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/lens/Iso.java | 51 +++++++++++++------ .../com/jnape/palatable/lambda/lens/Lens.java | 44 +++------------- .../jnape/palatable/lambda/lens/LensLike.java | 38 ++++++++++++++ 4 files changed, 83 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef274c415..042b5a5ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Added - `Fn3-8` static factory overloads to aid in coercing lambdas +- Adding composition guarantees to `LensLike` ## [3.0.3] - 2018-05-27 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java b/src/main/java/com/jnape/palatable/lambda/lens/Iso.java index 56caf718e..bff042842 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/Iso.java @@ -176,6 +176,11 @@ default Iso mapB(Function fn) { return unIso().biMapR(f -> f.compose(fn)).into(Iso::iso); } + @Override + default Lens andThen(LensLike f) { + return toLens().andThen(f); + } + /** * Left-to-right composition of {@link Iso}. * @@ -200,6 +205,11 @@ default Iso compose(Iso g) { return g.andThen(this); } + @Override + default Lens compose(LensLike f) { + return toLens().compose(f); + } + /** * Static factory method for creating an iso from a function and it's inverse. * @@ -243,23 +253,9 @@ static Iso.Simple simpleIso(Function f, Fun * @param the type of both "larger" values * @param the type of both "smaller" values */ + @FunctionalInterface interface Simple extends Iso, LensLike.Simple { - @Override - default Iso.Simple mirror() { - return adapt(Iso.super.mirror()); - } - - @Override - default Lens.Simple toLens() { - return Lens.Simple.adapt(Iso.super.toLens()); - } - - @Override - default Iso.Simple discardR(Applicative> appB) { - return adapt(Iso.super.discardR(appB)); - } - /** * Compose two simple isos from right to left. * @@ -282,6 +278,31 @@ default Iso.Simple andThen(Iso.Simple f) { return adapt(f.compose(this)); } + @Override + default Iso.Simple mirror() { + return adapt(Iso.super.mirror()); + } + + @Override + default Lens.Simple toLens() { + return Lens.Simple.adapt(Iso.super.toLens()); + } + + @Override + default Iso.Simple discardR(Applicative> appB) { + return adapt(Iso.super.discardR(appB)); + } + + @Override + default Lens.Simple compose(LensLike.Simple g) { + return toLens().compose(g); + } + + @Override + default Lens.Simple andThen(LensLike.Simple f) { + return toLens().andThen(f); + } + /** * Adapt an {@link Iso} with the right variance to an {@link Iso.Simple}. * 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 3b5ac1f75..3f832d351 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/Lens.java @@ -220,27 +220,13 @@ 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. - * - * @param f the other lens - * @param the new "smaller" value to read (previously A) - * @param the new "smaller" update value (previously B) - * @return the composed lens - */ - default Lens andThen(Lens f) { - return f.compose(this); + @Override + default Lens andThen(LensLike f) { + return lens(view(this).fmap(view(f)), (q, b) -> over(this, set(f, b), q)); } - /** - * Right-to-left composition of lenses. Requires compatibility between A and B. - * - * @param g the other lens - * @param the new "larger" value for reading (previously S) - * @param the new "larger" value for putting (previously T) - * @return the composed lens - */ - default Lens compose(Lens g) { + @Override + default Lens compose(LensLike g) { return lens(view(g).fmap(view(this)), (q, b) -> over(g, set(this, b), q)); } @@ -323,26 +309,12 @@ static Lens.Simple> both(Lens.Simple f, Lens.Sim @FunctionalInterface interface Simple extends Lens, LensLike.Simple { - /** - * Compose two simple lenses from right to left. - * - * @param g the other simple lens - * @param the other simple lens' larger type - * @return the composed simple lens - */ - default Lens.Simple compose(Lens.Simple g) { + default Lens.Simple compose(LensLike.Simple g) { return Lens.Simple.adapt(Lens.super.compose(g)); } - /** - * Compose two simple lenses from left to right. - * - * @param f the other simple lens - * @param the other simple lens' smaller type - * @return the composed simple lens - */ - default Lens.Simple andThen(Lens.Simple f) { - return f.compose(this); + default Lens.Simple andThen(LensLike.Simple f) { + return Lens.Simple.adapt(Lens.super.andThen(f)); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java b/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java index 7b8b699f6..5551e172a 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java @@ -25,6 +25,26 @@ public interface LensLike extends Monad, FB extends Functor> FT apply( Function fn, S s); + /** + * Right-to-left composition of lenses. Requires compatibility between A and B. + * + * @param g the other lens + * @param the new "larger" value for reading (previously S) + * @param the new "larger" value for putting (previously T) + * @return the composed lens + */ + LensLike compose(LensLike g); + + /** + * Left-to-right composition of lenses. Requires compatibility between S and T. + * + * @param f the other lens + * @param the new "smaller" value to read (previously A) + * @param the new "smaller" update value (previously B) + * @return the composed lens + */ + LensLike andThen(LensLike f); + /** * Contravariantly map S to R, yielding a new lens. * @@ -117,5 +137,23 @@ default LensLike contraMap(Function * @param the concrete lens subtype */ interface Simple extends LensLike { + + /** + * Compose two simple lenses from right to left. + * + * @param g the other simple lens + * @param the other simple lens' larger type + * @return the composed simple lens + */ + LensLike.Simple compose(LensLike.Simple g); + + /** + * Compose two simple lenses from left to right. + * + * @param f the other simple lens + * @param the other simple lens' smaller type + * @return the composed simple lens + */ + LensLike.Simple andThen(LensLike.Simple f); } } From f031e224a49682d4a7253d8c1ffa2db4c25e77c4 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 9 Jun 2018 18:53:00 -0500 Subject: [PATCH 032/348] Adding inequality functions --- CHANGELOG.md | 1 + .../lambda/functions/builtin/fn2/CmpEq.java | 43 +++++++++++++ .../lambda/functions/builtin/fn2/GT.java | 42 +++++++++++++ .../lambda/functions/builtin/fn2/GTE.java | 42 +++++++++++++ .../lambda/functions/builtin/fn2/LT.java | 42 +++++++++++++ .../lambda/functions/builtin/fn2/LTE.java | 42 +++++++++++++ .../lambda/functions/builtin/fn3/CmpEqBy.java | 59 ++++++++++++++++++ .../lambda/functions/builtin/fn3/GTBy.java | 58 ++++++++++++++++++ .../lambda/functions/builtin/fn3/GTEBy.java | 61 +++++++++++++++++++ .../lambda/functions/builtin/fn3/LTBy.java | 58 ++++++++++++++++++ .../lambda/functions/builtin/fn3/LTEBy.java | 61 +++++++++++++++++++ .../functions/builtin/fn2/CmpEqTest.java | 17 ++++++ .../lambda/functions/builtin/fn2/GTETest.java | 17 ++++++ .../lambda/functions/builtin/fn2/GTTest.java | 16 +++++ .../lambda/functions/builtin/fn2/LTETest.java | 17 ++++++ .../lambda/functions/builtin/fn2/LTTest.java | 17 ++++++ .../functions/builtin/fn3/CmpEqByTest.java | 20 ++++++ .../functions/builtin/fn3/GTByTest.java | 20 ++++++ .../functions/builtin/fn3/GTEByTest.java | 21 +++++++ .../functions/builtin/fn3/LTByTest.java | 20 ++++++ .../functions/builtin/fn3/LTEByTest.java | 21 +++++++ 21 files changed, 695 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEqTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTETest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTETest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqByTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTByTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEByTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTByTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEByTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 042b5a5ac..78293d2f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `Fn3-8` static factory overloads to aid in coercing lambdas - Adding composition guarantees to `LensLike` +- `CmpEqBy`, `CmpEq`, `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` inequality checks ## [3.0.3] - 2018-05-27 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java new file mode 100644 index 000000000..132dec5c7 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java @@ -0,0 +1,43 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy; + +/** + * Given two {@link Comparable} values of type A, return true if the first value is strictly + * equal to the second value (according to {@link Comparable#compareTo(Object)}; otherwise, return false. + * + * @param the value type + * @see CmpEqBy + * @see LT + * @see GT + */ +public final class CmpEq> implements BiPredicate { + + private static final CmpEq INSTANCE = new CmpEq(); + + private CmpEq() { + } + + @Override + public Boolean apply(A x, A y) { + return cmpEqBy(id(), x, y); + } + + @SuppressWarnings("unchecked") + public static > CmpEq cmpEq() { + return INSTANCE; + } + + public static > Predicate cmpEq(A x) { + return CmpEq.cmpEq().apply(x); + } + + public static > Boolean cmpEq(A x, A y) { + return cmpEq(x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java new file mode 100644 index 000000000..d59094c63 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java @@ -0,0 +1,42 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.builtin.fn3.GTBy; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTBy.gtBy; + +/** + * Given two {@link Comparable} values of type A, return true if the first value is strictly + * greater than the second value; otherwise, return false. + * + * @param the value type + * @see GTBy + * @see LT + */ +public final class GT> implements BiPredicate { + + private static final GT INSTANCE = new GT(); + + private GT() { + } + + @Override + public Boolean apply(A x, A y) { + return gtBy(id(), x, y); + } + + @SuppressWarnings("unchecked") + public static > GT gt() { + return INSTANCE; + } + + public static > Predicate gt(A x) { + return GT.gt().apply(x); + } + + public static > Boolean gt(A x, A y) { + return gt(x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java new file mode 100644 index 000000000..436285300 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java @@ -0,0 +1,42 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.builtin.fn3.GTEBy; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTEBy.gteBy; + +/** + * Given two {@link Comparable} values of type A, return true if the first value is greater + * than or equal to the second value according to {@link Comparable#compareTo(Object)}; otherwise, return false. + * + * @param the value type + * @see GTEBy + * @see LTE + */ +public final class GTE> implements BiPredicate { + + private static final GTE INSTANCE = new GTE(); + + private GTE() { + } + + @Override + public Boolean apply(A x, A y) { + return gteBy(id(), x, y); + } + + @SuppressWarnings("unchecked") + public static > GTE gte() { + return INSTANCE; + } + + public static > Predicate gte(A x) { + return GTE.gte().apply(x); + } + + public static > Boolean gte(A x, A y) { + return gte(x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java new file mode 100644 index 000000000..f4906bf09 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java @@ -0,0 +1,42 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.builtin.fn3.LTBy; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTBy.ltBy; + +/** + * Given two {@link Comparable} values of type A, return true if the first value is strictly + * less than the second value; otherwise, return false. + * + * @param the value type + * @see LTBy + * @see GT + */ +public final class LT> implements BiPredicate { + + private static final LT INSTANCE = new LT(); + + private LT() { + } + + @Override + public Boolean apply(A x, A y) { + return ltBy(id(), x, y); + } + + @SuppressWarnings("unchecked") + public static > LT lt() { + return INSTANCE; + } + + public static > Predicate lt(A x) { + return LT.lt().apply(x); + } + + public static > Boolean lt(A x, A y) { + return lt(x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java new file mode 100644 index 000000000..6e5f1f33e --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java @@ -0,0 +1,42 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.builtin.fn3.LTEBy; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTEBy.lteBy; + +/** + * Given two {@link Comparable} values of type A, return true if the first value is less than + * or equal to the second value according to {@link Comparable#compareTo(Object);} otherwise, return false. + * + * @param the value typ + * @see LTEBy + * @see GTE + */ +public final class LTE> implements BiPredicate { + + private static final LTE INSTANCE = new LTE(); + + private LTE() { + } + + @Override + public Boolean apply(A x, A y) { + return lteBy(id(), x, y); + } + + @SuppressWarnings("unchecked") + public static > LTE lte() { + return INSTANCE; + } + + public static > Predicate lte(A x) { + return LTE.lte().apply(x); + } + + public static > Boolean lte(A x, A y) { + return lte(x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java new file mode 100644 index 000000000..156c51413 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java @@ -0,0 +1,59 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.builtin.fn2.CmpEq; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.function.Function; + +/** + * Given a mapping function from some type A to some {@link Comparable} type B and two values + * of type A, return true if the first value is strictly equal to the second value (according + * to {@link Comparable#compareTo(Object)} in terms of their mapped B results; otherwise, return false. + * + * @param the value type + * @param the mapped comparison type + * @see CmpEq + * @see LTBy + * @see GTBy + */ +public final class CmpEqBy> implements Fn3, A, A, Boolean> { + + private static final CmpEqBy INSTANCE = new CmpEqBy(); + + private CmpEqBy() { + } + + @Override + public Boolean apply(Function compareFn, A x, A y) { + return compareFn.apply(x).compareTo(compareFn.apply(y)) == 0; + } + + @Override + public BiPredicate apply(Function compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Function compareFn, A x) { + return Fn3.super.apply(compareFn, x)::apply; + } + + @SuppressWarnings("unchecked") + public static > CmpEqBy cmpEqBy() { + return INSTANCE; + } + + public static > BiPredicate cmpEqBy(Function compareFn) { + return CmpEqBy.cmpEqBy().apply(compareFn); + } + + public static > Predicate cmpEqBy(Function compareFn, A x) { + return CmpEqBy.cmpEqBy(compareFn).apply(x); + } + + public static > Boolean cmpEqBy(Function compareFn, A x, A y) { + return cmpEqBy(compareFn, x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java new file mode 100644 index 000000000..e3df534df --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java @@ -0,0 +1,58 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.builtin.fn2.GT; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.function.Function; + +/** + * Given a mapping function from some type A to some {@link Comparable} type B and two values + * of type A, return true if the first value is strictly greater than the second value in + * terms of their mapped B results; otherwise, return false. + * + * @param the value type + * @param the mapped comparison type + * @see GT + * @see LTBy + */ +public final class GTBy> implements Fn3, A, A, Boolean> { + + private static final GTBy INSTANCE = new GTBy(); + + private GTBy() { + } + + @Override + public Boolean apply(Function compareFn, A x, A y) { + return compareFn.apply(x).compareTo(compareFn.apply(y)) > 0; + } + + @Override + public BiPredicate apply(Function compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Function compareFn, A x) { + return Fn3.super.apply(compareFn, x)::apply; + } + + @SuppressWarnings("unchecked") + public static > GTBy gtBy() { + return INSTANCE; + } + + public static > BiPredicate gtBy(Function fn) { + return GTBy.gtBy().apply(fn); + } + + public static > Predicate gtBy(Function fn, A x) { + return GTBy.gtBy(fn).apply(x); + } + + public static > Boolean gtBy(Function fn, A x, A y) { + return gtBy(fn, x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java new file mode 100644 index 000000000..bbc26c686 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java @@ -0,0 +1,61 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.builtin.fn2.GTE; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy; + +/** + * Given a mapping function from some type A to some {@link Comparable} type B and two values + * of type A, return true if the first value is greater than or equal to the second value in + * terms of their mapped B results according to {@link Comparable#compareTo(Object)}; otherwise, return + * false. + * + * @param the value type + * @param the mapped comparison type + * @see GTE + * @see LTEBy + */ +public final class GTEBy> implements Fn3, A, A, Boolean> { + + private static final GTEBy INSTANCE = new GTEBy(); + + private GTEBy() { + } + + @Override + public Boolean apply(Function compareFn, A x, A y) { + return GTBy.gtBy(compareFn).or(cmpEqBy(compareFn)).apply(x, y); + } + + @Override + public BiPredicate apply(Function compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Function compareFn, A x) { + return Fn3.super.apply(compareFn, x)::apply; + } + + @SuppressWarnings("unchecked") + public static > GTEBy gteBy() { + return INSTANCE; + } + + public static > BiPredicate gteBy(Function fn) { + return GTEBy.gteBy().apply(fn); + } + + public static > Predicate gteBy(Function fn, A x) { + return GTEBy.gteBy(fn).apply(x); + } + + public static > Boolean gteBy(Function fn, A x, A y) { + return gteBy(fn, x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java new file mode 100644 index 000000000..5d7b57c79 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java @@ -0,0 +1,58 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.builtin.fn2.LT; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.function.Function; + +/** + * Given a mapping function from some type A to some {@link Comparable} type B and two values + * of type A, return true if the first value is strictly less than the second value in terms + * of their mapped B results; otherwise, return false. + * + * @param the value type + * @param the mapped comparison type + * @see LT + * @see GTBy + */ +public final class LTBy> implements Fn3, A, A, Boolean> { + + private static final LTBy INSTANCE = new LTBy(); + + private LTBy() { + } + + @Override + public Boolean apply(Function compareFn, A x, A y) { + return compareFn.apply(x).compareTo(compareFn.apply(y)) < 0; + } + + @Override + public BiPredicate apply(Function compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Function compareFn, A x) { + return Fn3.super.apply(compareFn, x)::apply; + } + + @SuppressWarnings("unchecked") + public static > LTBy ltBy() { + return INSTANCE; + } + + public static > BiPredicate ltBy(Function fn) { + return LTBy.ltBy().apply(fn); + } + + public static > Predicate ltBy(Function fn, A x) { + return LTBy.ltBy(fn).apply(x); + } + + public static > Boolean ltBy(Function fn, A x, A y) { + return ltBy(fn, x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java new file mode 100644 index 000000000..14ea8d6b5 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java @@ -0,0 +1,61 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.builtin.fn2.LTE; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy; + +/** + * Given a mapping function from some type A to some {@link Comparable} type B and two values + * of type A, return true if the first value is less than or equal to the second value in + * terms of their mapped B results according to {@link Comparable#compareTo(Object)}; otherwise, return + * false. + * + * @param the value type + * @param the mapped comparison type + * @see LTE + * @see GTEBy + */ +public final class LTEBy> implements Fn3, A, A, Boolean> { + + private static final LTEBy INSTANCE = new LTEBy(); + + private LTEBy() { + } + + @Override + public Boolean apply(Function compareFn, A x, A y) { + return LTBy.ltBy(compareFn).or(cmpEqBy(compareFn)).apply(x, y); + } + + @Override + public BiPredicate apply(Function compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Function compareFn, A x) { + return Fn3.super.apply(compareFn, x)::apply; + } + + @SuppressWarnings("unchecked") + public static > LTEBy lteBy() { + return INSTANCE; + } + + public static > BiPredicate lteBy(Function fn) { + return LTEBy.lteBy().apply(fn); + } + + public static > Predicate lteBy(Function fn, A x) { + return LTEBy.lteBy(fn).apply(x); + } + + public static > Boolean lteBy(Function fn, A x, A y) { + return lteBy(fn, x).apply(y); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEqTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEqTest.java new file mode 100644 index 000000000..05290241a --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEqTest.java @@ -0,0 +1,17 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.CmpEq.cmpEq; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class CmpEqTest { + + @Test + public void comparisons() { + assertTrue(cmpEq(1, 1)); + assertFalse(cmpEq(1, 2)); + assertFalse(cmpEq(2, 1)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTETest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTETest.java new file mode 100644 index 000000000..598869ab9 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTETest.java @@ -0,0 +1,17 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.GTE.gte; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GTETest { + + @Test + public void comparisons() { + assertTrue(gte(2, 1)); + assertTrue(gte(1, 1)); + assertFalse(gte(1, 2)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTTest.java new file mode 100644 index 000000000..7e73795ea --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTTest.java @@ -0,0 +1,16 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GTTest { + + @Test + public void comparisons() { + assertTrue(GT.gt(2, 1)); + assertFalse(GT.gt(1, 1)); + assertFalse(GT.gt(1, 2)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTETest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTETest.java new file mode 100644 index 000000000..14ba931c1 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTETest.java @@ -0,0 +1,17 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.LTE.lte; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class LTETest { + + @Test + public void comparisons() { + assertTrue(lte(1, 2)); + assertTrue(lte(1, 1)); + assertFalse(lte(2, 1)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTTest.java new file mode 100644 index 000000000..a72ec158f --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTTest.java @@ -0,0 +1,17 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.LT.lt; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class LTTest { + + @Test + public void comparisons() { + assertTrue(lt(1, 2)); + assertFalse(lt(1, 1)); + assertFalse(lt(2, 1)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqByTest.java new file mode 100644 index 000000000..4754ecf3e --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqByTest.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class CmpEqByTest { + + @Test + public void comparisons() { + assertTrue(cmpEqBy(id(), 1, 1)); + assertFalse(cmpEqBy(id(), 1, 2)); + assertFalse(cmpEqBy(id(), 2, 1)); + + assertTrue(cmpEqBy(String::length, "b", "a")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTByTest.java new file mode 100644 index 000000000..20e0c4e2a --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTByTest.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTBy.gtBy; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GTByTest { + + @Test + public void comparisons() { + assertTrue(gtBy(id(), 2, 1)); + assertFalse(gtBy(id(), 1, 1)); + assertFalse(gtBy(id(), 1, 2)); + + assertTrue(gtBy(String::length, "aaa", "bb")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEByTest.java new file mode 100644 index 000000000..f363ccb34 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEByTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTEBy.gteBy; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GTEByTest { + + @Test + public void comparisons() { + assertTrue(gteBy(id(), 2, 1)); + assertTrue(gteBy(id(), 1, 1)); + assertFalse(gteBy(id(), 1, 2)); + + assertTrue(gteBy(String::length, "ab", "b")); + assertTrue(gteBy(String::length, "ab", "bc")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTByTest.java new file mode 100644 index 000000000..c06db00b9 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTByTest.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTBy.ltBy; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class LTByTest { + + @Test + public void comparisons() { + assertTrue(ltBy(id(), 1, 2)); + assertFalse(ltBy(id(), 1, 1)); + assertFalse(ltBy(id(), 2, 1)); + + assertTrue(ltBy(String::length, "b", "ab")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEByTest.java new file mode 100644 index 000000000..44cc71ef5 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEByTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTEBy.lteBy; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class LTEByTest { + + @Test + public void comparisons() { + assertTrue(lteBy(id(), 1, 2)); + assertTrue(lteBy(id(), 1, 1)); + assertFalse(lteBy(id(), 2, 1)); + + assertTrue(lteBy(String::length, "b", "ab")); + assertTrue(lteBy(String::length, "bc", "ab")); + } +} \ No newline at end of file From 4161dddb43f9098c02448400d30a41b4373c4f6e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 10 Jun 2018 14:44:58 -0500 Subject: [PATCH 033/348] Max/Min/-By semigroups --- CHANGELOG.md | 1 + .../lambda/semigroup/builtin/Max.java | 45 ++++++++++++++++ .../lambda/semigroup/builtin/MaxBy.java | 54 +++++++++++++++++++ .../lambda/semigroup/builtin/Min.java | 45 ++++++++++++++++ .../lambda/semigroup/builtin/MinBy.java | 54 +++++++++++++++++++ .../lambda/semigroup/builtin/MaxByTest.java | 21 ++++++++ .../lambda/semigroup/builtin/MaxTest.java | 16 ++++++ .../lambda/semigroup/builtin/MinByTest.java | 21 ++++++++ .../lambda/semigroup/builtin/MinTest.java | 16 ++++++ 9 files changed, 273 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java create mode 100644 src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java create mode 100644 src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java create mode 100644 src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java create mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxByTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinByTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 78293d2f1..45e48b10d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Fn3-8` static factory overloads to aid in coercing lambdas - Adding composition guarantees to `LensLike` - `CmpEqBy`, `CmpEq`, `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` inequality checks +- `MinBy`, `MaxBy`, `Min`, and `Max` semigroups ## [3.0.3] - 2018-05-27 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java new file mode 100644 index 000000000..3687a5187 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java @@ -0,0 +1,45 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.semigroup.builtin.MaxBy.maxBy; + +/** + * A {@link Semigroup} over A that chooses between two values x and y via the + * following rules: + *
    + *
  • If x is strictly less than y, return y
  • + *
  • Otherwise, return x
  • + *
+ * + * @param
the value type + * @see MaxBy + * @see Min + */ +public final class Max> implements Semigroup { + + private static final Max INSTANCE = new Max(); + + private Max() { + } + + @Override + public A apply(A x, A y) { + return maxBy(id(), x, y); + } + + @SuppressWarnings("unchecked") + public static > Max max() { + return INSTANCE; + } + + public static > Fn1 max(A x) { + return Max.max().apply(x); + } + + public static > A max(A x, A y) { + return max(x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java new file mode 100644 index 000000000..a5bbcce84 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java @@ -0,0 +1,54 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTBy.ltBy; + +/** + * Given a mapping function from some type A to some {@link Comparable} type B, produce a + * {@link Semigroup} over A that chooses between two values x and y via the + * following rules: + *
    + *
  • If x is strictly less than y in terms of B, return y
  • + *
  • Otherwise, return x
  • + *
+ * + * @param
the value type + * @param the mapped comparison type + * @see Max + * @see MinBy + */ +public final class MaxBy> implements SemigroupFactory, A> { + + private static final MaxBy INSTANCE = new MaxBy(); + + private MaxBy() { + } + + @Override + public Semigroup apply(Function compareFn) { + return (x, y) -> ltBy(compareFn, x, y) ? y : x; + } + + @SuppressWarnings("unchecked") + public static > MaxBy maxBy() { + return INSTANCE; + } + + public static > Semigroup maxBy( + Function compareFn) { + return MaxBy.maxBy().apply(compareFn); + } + + public static > Fn1 maxBy(Function compareFn, A x) { + return MaxBy.maxBy(compareFn).apply(x); + } + + public static > A maxBy(Function compareFn, A x, A y) { + return maxBy(compareFn, x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java new file mode 100644 index 000000000..742055ed5 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java @@ -0,0 +1,45 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.semigroup.builtin.MinBy.minBy; + +/** + * A {@link Semigroup} over A that chooses between two values x and y via the + * following rules: + *
    + *
  • If x is strictly greater than y, return y
  • + *
  • Otherwise, return x
  • + *
+ * + * @param
the value type + * @see MinBy + * @see Max + */ +public final class Min> implements Semigroup { + + private static final Min INSTANCE = new Min(); + + private Min() { + } + + @Override + public A apply(A x, A y) { + return minBy(id(), x, y); + } + + @SuppressWarnings("unchecked") + public static > Min min() { + return INSTANCE; + } + + public static > Fn1 min(A x) { + return Min.min().apply(x); + } + + public static > A min(A x, A y) { + return min(x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java new file mode 100644 index 000000000..7803d8ebd --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java @@ -0,0 +1,54 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTBy.gtBy; + +/** + * Given a mapping function from some type A to some {@link Comparable} type B, produce a + * {@link Semigroup} over A that chooses between two values x and y via the + * following rules: + *
    + *
  • If x is strictly greater than y in terms of B, return y
  • + *
  • Otherwise, return x
  • + *
+ * + * @param
the value type + * @param the mapped comparison type + * @see Min + * @see MaxBy + */ +public final class MinBy> implements SemigroupFactory, A> { + + private static final MinBy INSTANCE = new MinBy(); + + private MinBy() { + } + + @Override + public Semigroup apply(Function compareFn) { + return (x, y) -> gtBy(compareFn, x, y) ? y : x; + } + + @SuppressWarnings("unchecked") + public static > MinBy minBy() { + return INSTANCE; + } + + public static > Semigroup minBy( + Function compareFn) { + return MinBy.minBy().apply(compareFn); + } + + public static > Fn1 minBy(Function compareFn, A x) { + return MinBy.minBy(compareFn).apply(x); + } + + public static > A minBy(Function compareFn, A x, A y) { + return minBy(compareFn, x).apply(y); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxByTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxByTest.java new file mode 100644 index 000000000..a47fb0f30 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxByTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.semigroup.builtin.MaxBy.maxBy; +import static org.junit.Assert.assertEquals; + +public class MaxByTest { + + @Test + public void semigroup() { + assertEquals((Integer) 1, maxBy(id(), 1, 0)); + assertEquals((Integer) 1, maxBy(id(), 1, 1)); + assertEquals((Integer) 2, maxBy(id(), 1, 2)); + + assertEquals("ab", maxBy(String::length, "ab", "a")); + assertEquals("ab", maxBy(String::length, "ab", "cd")); + assertEquals("bc", maxBy(String::length, "a", "bc")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxTest.java new file mode 100644 index 000000000..5e18a7bcf --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxTest.java @@ -0,0 +1,16 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.semigroup.builtin.Max.max; +import static org.junit.Assert.assertEquals; + +public class MaxTest { + + @Test + public void semigroup() { + assertEquals((Integer) 1, max(1, 0)); + assertEquals((Integer) 1, max(1, 1)); + assertEquals((Integer) 2, max(1, 2)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinByTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinByTest.java new file mode 100644 index 000000000..5436b289e --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinByTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.semigroup.builtin.MinBy.minBy; +import static org.junit.Assert.assertEquals; + +public class MinByTest { + + @Test + public void semigroup() { + assertEquals((Integer) 1, minBy(id(), 1, 2)); + assertEquals((Integer) 1, minBy(id(), 1, 1)); + assertEquals((Integer) 0, minBy(id(), 1, 0)); + + assertEquals("a", minBy(String::length, "a", "ab")); + assertEquals("ab", minBy(String::length, "ab", "cd")); + assertEquals("c", minBy(String::length, "ab", "c")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinTest.java new file mode 100644 index 000000000..22e4ee3a0 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinTest.java @@ -0,0 +1,16 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.semigroup.builtin.Min.min; +import static org.junit.Assert.assertEquals; + +public class MinTest { + + @Test + public void semigroup() { + assertEquals((Integer) 1, min(1, 2)); + assertEquals((Integer) 1, min(1, 1)); + assertEquals((Integer) 0, min(1, 0)); + } +} \ No newline at end of file From e3e20484760b029e17081ce135eefec4ba6b8da5 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 20 May 2018 16:45:06 -0500 Subject: [PATCH 034/348] Tuples are now generalized products --- .../palatable/lambda/adt/hlist/Tuple2.java | 35 +++------ .../palatable/lambda/adt/hlist/Tuple3.java | 42 +++-------- .../palatable/lambda/adt/hlist/Tuple4.java | 48 +++--------- .../palatable/lambda/adt/hlist/Tuple5.java | 54 ++++---------- .../palatable/lambda/adt/hlist/Tuple6.java | 60 ++++----------- .../palatable/lambda/adt/hlist/Tuple7.java | 67 ++++------------- .../palatable/lambda/adt/hlist/Tuple8.java | 73 ++++--------------- .../lambda/adt/product/Product2.java | 44 +++++++++++ .../lambda/adt/product/Product3.java | 35 +++++++++ .../lambda/adt/product/Product4.java | 36 +++++++++ .../lambda/adt/product/Product5.java | 38 ++++++++++ .../lambda/adt/product/Product6.java | 39 ++++++++++ .../lambda/adt/product/Product7.java | 41 +++++++++++ .../lambda/adt/product/Product8.java | 42 +++++++++++ .../lambda/functions/builtin/fn2/Into4.java | 2 +- .../lambda/functions/builtin/fn2/Into5.java | 2 +- .../lambda/functions/builtin/fn2/Into6.java | 2 +- .../lambda/functions/builtin/fn2/Into7.java | 2 +- .../lambda/functions/builtin/fn2/Into8.java | 2 +- 19 files changed, 371 insertions(+), 293 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java create mode 100644 src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java create mode 100644 src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java create mode 100644 src/main/java/com/jnape/palatable/lambda/adt/product/Product5.java create mode 100644 src/main/java/com/jnape/palatable/lambda/adt/product/Product6.java create mode 100644 src/main/java/com/jnape/palatable/lambda/adt/product/Product7.java create mode 100644 src/main/java/com/jnape/palatable/lambda/adt/product/Product8.java 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 173bed228..f59f77d71 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,13 +1,13 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Map; -import java.util.function.BiFunction; import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -17,14 +17,19 @@ * * @param <_1> The first slot element type * @param <_2> The second slot element type + * @see Product2 * @see HList * @see SingletonHList * @see Tuple3 * @see Tuple4 * @see Tuple5 */ -public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> - implements Map.Entry<_1, _2>, Monad<_2, Tuple2<_1, ?>>, Bifunctor<_1, _2, Tuple2>, Traversable<_2, Tuple2<_1, ?>> { +public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements + Product2<_1, _2>, + Map.Entry<_1, _2>, + Monad<_2, Tuple2<_1, ?>>, + Bifunctor<_1, _2, Tuple2>, + Traversable<_2, Tuple2<_1, ?>> { private final _1 _1; private final _2 _2; @@ -40,36 +45,16 @@ 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 - */ + @Override public _1 _1() { return _1; } - /** - * Retrieve the second element in constant time. - * - * @return the second element - */ + @Override public _2 _2() { return _2; } - /** - * Destructure and apply this tuple to a function accepting the same number of arguments as this tuple's - * slots. This can be thought of as a kind of dual to uncurrying a function and applying a tuple to it. - * - * @param fn the function to apply - * @param the return type of the function - * @return the result of applying the destructured tuple to the function - */ - public R into(BiFunction fn) { - return fn.apply(_1, _2); - } - @Override public _1 getKey() { return _1(); 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 55ddb87b5..235b5bf30 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,7 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; -import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.adt.product.Product3; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -17,14 +17,19 @@ * @param <_1> The first slot element type * @param <_2> The second slot element type * @param <_3> The third slot element type + * @see Product3 * @see HList * @see SingletonHList * @see Tuple2 * @see Tuple4 * @see Tuple5 */ -public class Tuple3<_1, _2, _3> extends HCons<_1, Tuple2<_2, _3>> - implements Monad<_3, Tuple3<_1, _2, ?>>, Bifunctor<_2, _3, Tuple3<_1, ?, ?>>, Traversable<_3, Tuple3<_1, _2, ?>> { +public class Tuple3<_1, _2, _3> extends HCons<_1, Tuple2<_2, _3>> implements + Product3<_1, _2, _3>, + Monad<_3, Tuple3<_1, _2, ?>>, + Bifunctor<_2, _3, Tuple3<_1, ?, ?>>, + Traversable<_3, Tuple3<_1, _2, ?>> { + private final _1 _1; private final _2 _2; private final _3 _3; @@ -41,46 +46,21 @@ 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 - */ + @Override public _1 _1() { return _1; } - /** - * Retrieve the second element in constant time. - * - * @return the second element - */ + @Override public _2 _2() { return _2; } - /** - * Retrieve the third element in constant time. - * - * @return the third element - */ + @Override public _3 _3() { return _3; } - /** - * Destructure and apply this tuple to a function accepting the same number of arguments as this tuple's - * slots. - * - * @param fn the function to apply - * @param the return type of the function - * @return the result of applying the destructured tuple to the function - * @see Tuple2#into - */ - public R into(Fn3 fn) { - return fn.apply(_1, _2, _3); - } - @Override @SuppressWarnings("unchecked") public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Function fn) { 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 92347c62a..f24d1cca2 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,7 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; -import com.jnape.palatable.lambda.functions.Fn4; +import com.jnape.palatable.lambda.adt.product.Product4; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -18,14 +18,19 @@ * @param <_2> The second slot element type * @param <_3> The third slot element type * @param <_4> The fourth slot element type + * @see Product4 * @see HList * @see SingletonHList * @see Tuple2 * @see Tuple3 * @see Tuple5 */ -public class Tuple4<_1, _2, _3, _4> extends HCons<_1, Tuple3<_2, _3, _4>> - implements Monad<_4, Tuple4<_1, _2, _3, ?>>, Bifunctor<_3, _4, Tuple4<_1, _2, ?, ?>>, Traversable<_4, Tuple4<_1, _2, _3, ?>> { +public class Tuple4<_1, _2, _3, _4> extends HCons<_1, Tuple3<_2, _3, _4>> implements + Product4<_1, _2, _3, _4>, + Monad<_4, Tuple4<_1, _2, _3, ?>>, + Bifunctor<_3, _4, Tuple4<_1, _2, ?, ?>>, + Traversable<_4, Tuple4<_1, _2, _3, ?>> { + private final _1 _1; private final _2 _2; private final _3 _3; @@ -44,55 +49,26 @@ 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 - */ + @Override public _1 _1() { return _1; } - /** - * Retrieve the second element in constant time. - * - * @return the second element - */ + @Override public _2 _2() { return _2; } - /** - * Retrieve the third element in constant time. - * - * @return the third element - */ + @Override public _3 _3() { return _3; } - /** - * Retrieve the fourth element in constant time. - * - * @return the fourth element - */ + @Override public _4 _4() { return _4; } - /** - * Destructure and apply this tuple to a function accepting the same number of arguments as this tuple's - * slots. - * - * @param fn the function to apply - * @param the return type of the function - * @return the result of applying the destructured tuple to the function - * @see Tuple2#into - */ - public R into(Fn4 fn) { - return fn.apply(_1, _2, _3, _4); - } - @Override @SuppressWarnings("unchecked") public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(Function fn) { 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 d087d4a48..9936cc243 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,7 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; -import com.jnape.palatable.lambda.functions.Fn5; +import com.jnape.palatable.lambda.adt.product.Product5; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -19,14 +19,19 @@ * @param <_3> The third slot element type * @param <_4> The fourth slot element type * @param <_5> The fifth slot element type + * @see Product5 * @see HList * @see SingletonHList * @see Tuple2 * @see Tuple3 * @see Tuple4 */ -public class Tuple5<_1, _2, _3, _4, _5> extends HCons<_1, Tuple4<_2, _3, _4, _5>> - implements Monad<_5, Tuple5<_1, _2, _3, _4, ?>>, Bifunctor<_4, _5, Tuple5<_1, _2, _3, ?, ?>>, Traversable<_5, Tuple5<_1, _2, _3, _4, ?>> { +public class Tuple5<_1, _2, _3, _4, _5> extends HCons<_1, Tuple4<_2, _3, _4, _5>> implements + Product5<_1, _2, _3, _4, _5>, + Monad<_5, Tuple5<_1, _2, _3, _4, ?>>, + Bifunctor<_4, _5, Tuple5<_1, _2, _3, ?, ?>>, + Traversable<_5, Tuple5<_1, _2, _3, _4, ?>> { + private final _1 _1; private final _2 _2; private final _3 _3; @@ -47,64 +52,31 @@ public <_0> Tuple6<_0, _1, _2, _3, _4, _5> cons(_0 _0) { return new Tuple6<>(_0, this); } - /** - * Retrieve the first (head) element in constant time. - * - * @return the head element - */ + @Override public _1 _1() { return _1; } - /** - * Retrieve the second element in constant time. - * - * @return the second element - */ + @Override public _2 _2() { return _2; } - /** - * Retrieve the third element in constant time. - * - * @return the third element - */ + @Override public _3 _3() { return _3; } - /** - * Retrieve the fourth element in constant time. - * - * @return the fourth element - */ + @Override public _4 _4() { return _4; } - /** - * Retrieve the fifth element in constant time. - * - * @return the fifth element - */ + @Override public _5 _5() { return _5; } - /** - * Destructure and apply this tuple to a function accepting the same number of arguments as this tuple's - * slots. - * - * @param fn the function to apply - * @param the return type of the function - * @return the result of applying the destructured tuple to the function - * @see Tuple2#into - */ - public R into(Fn5 fn) { - return fn.apply(_1, _2, _3, _4, _5); - } - @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Function fn) { return Monad.super.<_5Prime>fmap(fn).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 2d7e21ab6..1cdbbb343 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; -import com.jnape.palatable.lambda.functions.Fn6; +import com.jnape.palatable.lambda.adt.product.Product6; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -20,6 +20,7 @@ * @param <_4> The fourth slot element type * @param <_5> The fifth slot element type * @param <_6> The sixth slot element type + * @see Product6 * @see HList * @see SingletonHList * @see Tuple2 @@ -27,8 +28,12 @@ * @see Tuple4 * @see Tuple5 */ -public class Tuple6<_1, _2, _3, _4, _5, _6> extends HCons<_1, Tuple5<_2, _3, _4, _5, _6>> - implements Monad<_6, Tuple6<_1, _2, _3, _4, _5, ?>>, Bifunctor<_5, _6, Tuple6<_1, _2, _3, _4, ?, ?>>, Traversable<_6, Tuple6<_1, _2, _3, _4, _5, ?>> { +public class Tuple6<_1, _2, _3, _4, _5, _6> extends HCons<_1, Tuple5<_2, _3, _4, _5, _6>> implements + Product6<_1, _2, _3, _4, _5, _6>, + Monad<_6, Tuple6<_1, _2, _3, _4, _5, ?>>, + Bifunctor<_5, _6, Tuple6<_1, _2, _3, _4, ?, ?>>, + Traversable<_6, Tuple6<_1, _2, _3, _4, _5, ?>> { + private final _1 _1; private final _2 _2; private final _3 _3; @@ -51,73 +56,36 @@ public <_0> Tuple7<_0, _1, _2, _3, _4, _5, _6> cons(_0 _0) { return new Tuple7<>(_0, this); } - /** - * Retrieve the first (head) element in constant time. - * - * @return the head element - */ + @Override public _1 _1() { return _1; } - /** - * Retrieve the second element in constant time. - * - * @return the second element - */ + @Override public _2 _2() { return _2; } - /** - * Retrieve the third element in constant time. - * - * @return the third element - */ + @Override public _3 _3() { return _3; } - /** - * Retrieve the fourth element in constant time. - * - * @return the fourth element - */ + @Override public _4 _4() { return _4; } - /** - * Retrieve the fifth element in constant time. - * - * @return the fifth element - */ + @Override public _5 _5() { return _5; } - /** - * Retrieve the sixth element in constant time. - * - * @return the sixth element - */ + @Override public _6 _6() { return _6; } - /** - * Destructure and apply this tuple to a function accepting the same number of arguments as this tuple's - * slots. - * - * @param fn the function to apply - * @param the return type of the function - * @return the result of applying the destructured tuple to the function - * @see Tuple2#into - */ - public R into(Fn6 fn) { - return fn.apply(_1, _2, _3, _4, _5, _6); - } - @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> fmap(Function fn) { return Monad.super.<_6Prime>fmap(fn).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index 28f47406c..439137c20 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; -import com.jnape.palatable.lambda.functions.Fn7; +import com.jnape.palatable.lambda.adt.product.Product7; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -21,6 +21,7 @@ * @param <_5> The fifth slot element type * @param <_6> The sixth slot element type * @param <_7> The seventh slot element type + * @see Product7 * @see HList * @see SingletonHList * @see Tuple2 @@ -29,8 +30,12 @@ * @see Tuple5 * @see Tuple6 */ -public class Tuple7<_1, _2, _3, _4, _5, _6, _7> extends HCons<_1, Tuple6<_2, _3, _4, _5, _6, _7>> - implements Monad<_7, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, Bifunctor<_6, _7, Tuple7<_1, _2, _3, _4, _5, ?, ?>>, Traversable<_7, Tuple7<_1, _2, _3, _4, _5, _6, ?>> { +public class Tuple7<_1, _2, _3, _4, _5, _6, _7> extends HCons<_1, Tuple6<_2, _3, _4, _5, _6, _7>> implements + Product7<_1, _2, _3, _4, _5, _6, _7>, + Monad<_7, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, + Bifunctor<_6, _7, Tuple7<_1, _2, _3, _4, _5, ?, ?>>, + Traversable<_7, Tuple7<_1, _2, _3, _4, _5, _6, ?>> { + private final _1 _1; private final _2 _2; private final _3 _3; @@ -55,83 +60,41 @@ public <_0> Tuple8<_0, _1, _2, _3, _4, _5, _6, _7> cons(_0 _0) { return new Tuple8<>(_0, this); } - /** - * Retrieve the first (head) element in constant time. - * - * @return the head element - */ + @Override public _1 _1() { return _1; } - /** - * Retrieve the second element in constant time. - * - * @return the second element - */ + @Override public _2 _2() { return _2; } - /** - * Retrieve the third element in constant time. - * - * @return the third element - */ + @Override public _3 _3() { return _3; } - /** - * Retrieve the fourth element in constant time. - * - * @return the fourth element - */ + @Override public _4 _4() { return _4; } - /** - * Retrieve the fifth element in constant time. - * - * @return the fifth element - */ + @Override public _5 _5() { return _5; } - /** - * Retrieve the sixth element in constant time. - * - * @return the sixth element - */ + @Override public _6 _6() { return _6; } - /** - * Retrieve the seventh element in constant time. - * - * @return the seventh element - */ + @Override public _7 _7() { return _7; } - /** - * Destructure and apply this tuple to a function accepting the same number of arguments as this tuple's - * slots. - * - * @param fn the function to apply - * @param the return type of the function - * @return the result of applying the destructured tuple to the function - * @see Tuple2#into - */ - public R into( - Fn7 fn) { - return fn.apply(_1, _2, _3, _4, _5, _6, _7); - } - @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> fmap(Function fn) { return Monad.super.<_7Prime>fmap(fn).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 1226cc395..63b0279f4 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; -import com.jnape.palatable.lambda.functions.Fn8; +import com.jnape.palatable.lambda.adt.product.Product8; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -22,6 +22,7 @@ * @param <_6> The sixth slot element type * @param <_7> The seventh slot element type * @param <_8> The eighth slot element type + * @see Product8 * @see HList * @see SingletonHList * @see Tuple2 @@ -31,8 +32,12 @@ * @see Tuple6 * @see Tuple7 */ -public class Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> extends HCons<_1, Tuple7<_2, _3, _4, _5, _6, _7, _8>> - implements Monad<_8, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, Bifunctor<_7, _8, Tuple8<_1, _2, _3, _4, _5, _6, ?, ?>>, Traversable<_8, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> { +public class Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> extends HCons<_1, Tuple7<_2, _3, _4, _5, _6, _7, _8>> implements + Product8<_1, _2, _3, _4, _5, _6, _7, _8>, + Monad<_8, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, + Bifunctor<_7, _8, Tuple8<_1, _2, _3, _4, _5, _6, ?, ?>>, + Traversable<_8, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> { + private final _1 _1; private final _2 _2; private final _3 _3; @@ -59,92 +64,46 @@ public <_0> HCons<_0, Tuple8<_1, _2, _3, _4, _5, _6, _7, _8>> cons(_0 _0) { return new HCons<>(_0, this); } - /** - * Retrieve the first (head) element in constant time. - * - * @return the head element - */ + @Override public _1 _1() { return _1; } - /** - * Retrieve the second element in constant time. - * - * @return the second element - */ + @Override public _2 _2() { return _2; } - /** - * Retrieve the third element in constant time. - * - * @return the third element - */ + @Override public _3 _3() { return _3; } - /** - * Retrieve the fourth element in constant time. - * - * @return the fourth element - */ + @Override public _4 _4() { return _4; } - /** - * Retrieve the fifth element in constant time. - * - * @return the fifth element - */ + @Override public _5 _5() { return _5; } - /** - * Retrieve the sixth element in constant time. - * - * @return the sixth element - */ + @Override public _6 _6() { return _6; } - /** - * Retrieve the seventh element in constant time. - * - * @return the seventh element - */ + @Override public _7 _7() { return _7; } - /** - * Retrieve the eighth element in constant time. - * - * @return the eighth element - */ + @Override public _8 _8() { return _8; } - /** - * Destructure and apply this tuple to a function accepting the same number of arguments as this tuple's - * slots. - * - * @param fn the function to apply - * @param the return type of the function - * @return the result of applying the destructured tuple to the function - * @see Tuple2#into - */ - public R into( - Fn8 fn) { - return fn.apply(_1, _2, _3, _4, _5, _6, _7, _8); - } - @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> fmap(Function fn) { return Monad.super.<_8Prime>fmap(fn).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java new file mode 100644 index 000000000..bee695b01 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java @@ -0,0 +1,44 @@ +package com.jnape.palatable.lambda.adt.product; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; + +import java.util.function.BiFunction; + +/** + * The minimal shape of the combination of two potentially distinctly typed values, supporting destructuring via + * explicitly named indexing methods, as well as via a combining function. + *

+ * For more information, read about products. + * + * @param <_1> The first element type + * @param <_2> The second element type + * @see Tuple2 + */ +public interface Product2<_1, _2> { + + /** + * Retrieve the first element. + * + * @return the first element + */ + _1 _1(); + + /** + * Retrieve the second element. + * + * @return the second element + */ + _2 _2(); + + /** + * Destructure and apply this product to a function accepting the same number of arguments as this product's + * slots. This can be thought of as a kind of dual to uncurrying a function and applying a product to it. + * + * @param fn the function to apply + * @param the return type of the function + * @return the result of applying the destructured product to the function + */ + default R into(BiFunction fn) { + return fn.apply(_1(), _2()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java new file mode 100644 index 000000000..241c97c5f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java @@ -0,0 +1,35 @@ +package com.jnape.palatable.lambda.adt.product; + +import com.jnape.palatable.lambda.adt.hlist.Tuple3; +import com.jnape.palatable.lambda.functions.Fn3; + +/** + * A product with three values. + * + * @param <_1> The first element type + * @param <_2> The second element type + * @param <_3> The third element type + * @see Product2 + * @see Tuple3 + */ +public interface Product3<_1, _2, _3> extends Product2<_1, _2> { + + /** + * Retrieve the third element. + * + * @return the third element + */ + _3 _3(); + + /** + * Destructure and apply this product to a function accepting the same number of arguments as this product's + * slots. This can be thought of as a kind of dual to uncurrying a function and applying a product to it. + * + * @param fn the function to apply + * @param the return type of the function + * @return the result of applying the destructured product to the function + */ + default R into(Fn3 fn) { + return Product2.super.into(fn.toBiFunction()).apply(_3()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java new file mode 100644 index 000000000..554591ed5 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java @@ -0,0 +1,36 @@ +package com.jnape.palatable.lambda.adt.product; + +import com.jnape.palatable.lambda.adt.hlist.Tuple4; +import com.jnape.palatable.lambda.functions.Fn4; + +/** + * A product with four values. + * + * @param <_1> The first element type + * @param <_2> The second element type + * @param <_3> The third element type + * @param <_4> The fourth element type + * @see Product2 + * @see Tuple4 + */ +public interface Product4<_1, _2, _3, _4> extends Product3<_1, _2, _3> { + + /** + * Retrieve the fourth element. + * + * @return the fourth element + */ + _4 _4(); + + /** + * Destructure and apply this product to a function accepting the same number of arguments as this product's + * slots. This can be thought of as a kind of dual to uncurrying a function and applying a product to it. + * + * @param fn the function to apply + * @param the return type of the function + * @return the result of applying the destructured product to the function + */ + default R into(Fn4 fn) { + return Product3.super.into(fn).apply(_4()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product5.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product5.java new file mode 100644 index 000000000..144fc296c --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product5.java @@ -0,0 +1,38 @@ +package com.jnape.palatable.lambda.adt.product; + +import com.jnape.palatable.lambda.adt.hlist.Tuple5; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn5; + +/** + * A product with five values. + * + * @param <_1> The first 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 + * @see Product2 + * @see Tuple5 + */ +public interface Product5<_1, _2, _3, _4, _5> extends Product4<_1, _2, _3, _4> { + + /** + * Retrieve the fifth element. + * + * @return the fifth element + */ + _5 _5(); + + /** + * Destructure and apply this product to a function accepting the same number of arguments as this product's + * slots. This can be thought of as a kind of dual to uncurrying a function and applying a product to it. + * + * @param fn the function to apply + * @param the return type of the function + * @return the result of applying the destructured product to the function + */ + default R into(Fn5 fn) { + return Product4.super.>into(fn).apply(_5()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product6.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product6.java new file mode 100644 index 000000000..07b14a307 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product6.java @@ -0,0 +1,39 @@ +package com.jnape.palatable.lambda.adt.product; + +import com.jnape.palatable.lambda.adt.hlist.Tuple6; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn6; + +/** + * A product with six values. + * + * @param <_1> The first 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 + * @param <_6> The sixth element type + * @see Product2 + * @see Tuple6 + */ +public interface Product6<_1, _2, _3, _4, _5, _6> extends Product5<_1, _2, _3, _4, _5> { + + /** + * Retrieve the sixth element. + * + * @return the sixth element + */ + _6 _6(); + + /** + * Destructure and apply this product to a function accepting the same number of arguments as this product's + * slots. This can be thought of as a kind of dual to uncurrying a function and applying a product to it. + * + * @param fn the function to apply + * @param the return type of the function + * @return the result of applying the destructured product to the function + */ + default R into(Fn6 fn) { + return Product5.super.>into(fn).apply(_6()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product7.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product7.java new file mode 100644 index 000000000..0ea905148 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product7.java @@ -0,0 +1,41 @@ +package com.jnape.palatable.lambda.adt.product; + +import com.jnape.palatable.lambda.adt.hlist.Tuple7; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn7; + +/** + * A product with seven values. + * + * @param <_1> The first 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 + * @param <_6> The sixth element type + * @param <_7> The seventh element type + * @see Product2 + * @see Tuple7 + */ +public interface Product7<_1, _2, _3, _4, _5, _6, _7> extends Product6<_1, _2, _3, _4, _5, _6> { + + /** + * Retrieve the seventh element. + * + * @return the seventh element + */ + _7 _7(); + + /** + * Destructure and apply this product to a function accepting the same number of arguments as this product's + * slots. This can be thought of as a kind of dual to uncurrying a function and applying a product to it. + * + * @param fn the function to apply + * @param the return type of the function + * @return the result of applying the destructured product to the function + */ + default R into( + Fn7 fn) { + return Product6.super.>into(fn).apply(_7()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product8.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product8.java new file mode 100644 index 000000000..46fef4b86 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product8.java @@ -0,0 +1,42 @@ +package com.jnape.palatable.lambda.adt.product; + +import com.jnape.palatable.lambda.adt.hlist.Tuple8; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn8; + +/** + * A product with eight values. + * + * @param <_1> The first 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 + * @param <_6> The sixth element type + * @param <_7> The seventh element type + * @param <_8> The eighth element type + * @see Product2 + * @see Tuple8 + */ +public interface Product8<_1, _2, _3, _4, _5, _6, _7, _8> extends Product7<_1, _2, _3, _4, _5, _6, _7> { + + /** + * Retrieve the eighth element. + * + * @return the eighth element + */ + _8 _8(); + + /** + * Destructure and apply this product to a function accepting the same number of arguments as this product's + * slots. This can be thought of as a kind of dual to uncurrying a function and applying a product to it. + * + * @param fn the function to apply + * @param the return type of the function + * @return the result of applying the destructured product to the function + */ + default R into( + Fn8 fn) { + return Product7.super.>into(fn).apply(_8()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java index 240c0eb58..991495fc5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java @@ -21,7 +21,7 @@ public final class Into4 implements Fn2 fn, Tuple4 tuple) { - return tuple.into(fn); + return tuple.into(fn); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java index f74b6966c..d43e64997 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java @@ -23,7 +23,7 @@ public final class Into5 implements Fn2 fn, Tuple5 tuple) { - return tuple.into(fn); + return tuple.into(fn); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java index 50e68ef70..9ac76cc26 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java @@ -25,7 +25,7 @@ public final class Into6 implements Fn2 fn, Tuple6 tuple) { - return tuple.into(fn); + return tuple.into(fn); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java index c814d4b3e..6831e54ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java @@ -26,7 +26,7 @@ public final class Into7 implements Fn2 fn, Tuple7 tuple) { - return tuple.into(fn); + return tuple.into(fn); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java index 6ac77230b..6a214ccf0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java @@ -28,7 +28,7 @@ public final class Into8 implements Fn2 fn, Tuple8 tuple) { - return tuple.into(fn); + return tuple.into(fn); } @SuppressWarnings("unchecked") From f0559dec60fa3ba9bced5a350ae3d2e91087f237 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 20 May 2018 17:38:18 -0500 Subject: [PATCH 035/348] Fn1#uncurry and into* variants now accept general products --- CHANGELOG.md | 3 +++ .../jnape/palatable/lambda/functions/Fn2.java | 8 ++++---- .../jnape/palatable/lambda/functions/Fn3.java | 8 ++++---- .../jnape/palatable/lambda/functions/Fn4.java | 8 ++++---- .../jnape/palatable/lambda/functions/Fn5.java | 8 ++++---- .../jnape/palatable/lambda/functions/Fn6.java | 8 ++++---- .../jnape/palatable/lambda/functions/Fn7.java | 8 ++++---- .../jnape/palatable/lambda/functions/Fn8.java | 8 ++++---- .../lambda/functions/builtin/fn2/Into.java | 20 ++++++++++--------- .../lambda/functions/builtin/fn2/Into3.java | 19 +++++++++--------- .../lambda/functions/builtin/fn2/Into4.java | 18 ++++++++--------- .../lambda/functions/builtin/fn2/Into5.java | 18 ++++++++--------- .../lambda/functions/builtin/fn2/Into6.java | 18 ++++++++--------- .../lambda/functions/builtin/fn2/Into7.java | 18 ++++++++--------- .../lambda/functions/builtin/fn2/Into8.java | 18 ++++++++--------- .../specialized/BiMonoidFactory.java | 4 ++-- .../functions/specialized/BiPredicate.java | 4 ++-- .../specialized/BiSemigroupFactory.java | 4 ++-- .../functions/recursion/TrampolineTest.java | 3 ++- 19 files changed, 105 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45e48b10d..e67068a2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,9 +22,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [3.0.2] - 2018-05-21 ### Added - `IterableLens#mapping`, an `Iso` that maps values +- `Product2-8` interfaces, representing general product types ### Changed - `TypeSafeKey.Simple` now has a default `#apply` implementation +- `Tuple2-8` now implement `Product2-8` +- `Into2-8` now accepts a product of the same cardinality, instead of requiring a tuple ### Fixed - mapped `TypeSafeKey` instances can be used for initial put in an `HMap`, and the base key can be used to retrieve them diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index 712676d66..543273910 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -64,11 +64,11 @@ default Fn2 flip() { } /** - * Returns an {@link Fn1} that takes the arguments as a {@link Tuple2}<A, B>. + * Returns an {@link Fn1} that takes the arguments as a {@link Product2}<A, B>. * - * @return an {@link Fn1} taking a {@link Tuple2} + * @return an {@link Fn1} taking a {@link Product2} */ - default Fn1, C> uncurry() { + default Fn1, C> uncurry() { return (ab) -> apply(ab._1(), ab._2()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java index c0d073acd..4662543fe 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -64,13 +64,13 @@ default Fn3 flip() { } /** - * Returns an {@link Fn2} that takes the first two arguments as a {@link Tuple2}<A, B> and the + * Returns an {@link Fn2} that takes the first two arguments as a {@link Product2}<A, B> and the * third argument. * - * @return an {@link Fn2} taking a {@link Tuple2} and the third argument + * @return an {@link Fn2} taking a {@link Product2} and the third argument */ @Override - default Fn2, C, D> uncurry() { + default Fn2, C, D> uncurry() { return (ab, c) -> apply(ab._1(), ab._2(), c); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java index 6e71576c4..496fb3aad 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -79,13 +79,13 @@ default Fn4 flip() { } /** - * Returns an {@link Fn3} that takes the first two arguments as a {@link Tuple2}<A, B> and the + * Returns an {@link Fn3} that takes the first two arguments as a {@link Product2}<A, B> and the * third and fourth arguments. * - * @return an {@link Fn3} taking a {@link Tuple2} and the third and fourth arguments + * @return an {@link Fn3} taking a {@link Product2} and the third and fourth arguments */ @Override - default Fn3, C, D, E> uncurry() { + default Fn3, C, D, E> uncurry() { return (ab, c, d) -> apply(ab._1(), ab._2(), c, d); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java index 9c8b3affd..887e6c964 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -95,13 +95,13 @@ default Fn5 flip() { } /** - * Returns an {@link Fn4} that takes the first two arguments as a {@link Tuple2}<A, B> and the + * Returns an {@link Fn4} that takes the first two arguments as a {@link Product2}<A, B> and the * remaining arguments. * - * @return an {@link Fn4} taking a {@link Tuple2} and the remaining arguments + * @return an {@link Fn4} taking a {@link Product2} and the remaining arguments */ @Override - default Fn4, C, D, E, F> uncurry() { + default Fn4, C, D, E, F> uncurry() { return (ab, c, d, e) -> apply(ab._1(), ab._2(), c, d, e); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java index 5f55113cf..643a2a831 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -112,13 +112,13 @@ default Fn6 flip() { } /** - * Returns an {@link Fn5} that takes the first two arguments as a {@link Tuple2}<A, B> and the + * Returns an {@link Fn5} that takes the first two arguments as a {@link Product2}<A, B> and the * remaining arguments. * - * @return an {@link Fn5} taking a {@link Tuple2} and the remaining arguments + * @return an {@link Fn5} taking a {@link Product2} and the remaining arguments */ @Override - default Fn5, C, D, E, F, G> uncurry() { + default Fn5, C, D, E, F, G> uncurry() { return (ab, c, d, e, f) -> apply(ab._1(), ab._2(), c, d, e, f); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index 9ffe47762..6bf237963 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -130,13 +130,13 @@ default Fn7 flip() { } /** - * Returns an {@link Fn6} that takes the first two arguments as a {@link Tuple2}<A, B> and the + * Returns an {@link Fn6} that takes the first two arguments as a {@link Product2}<A, B> and the * remaining arguments. * - * @return an {@link Fn6} taking a {@link Tuple2} and the remaining arguments + * @return an {@link Fn6} taking a {@link Product2} and the remaining arguments */ @Override - default Fn6, C, D, E, F, G, H> uncurry() { + default Fn6, C, D, E, F, G, H> uncurry() { return (ab, c, d, e, f, g) -> apply(ab._1(), ab._2(), c, d, e, f, g); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java index f10f1aaf9..238c2f0a8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -147,13 +147,13 @@ default Fn8 flip() { } /** - * Returns an {@link Fn7} that takes the first two arguments as a {@link Tuple2}<A, B> and the + * Returns an {@link Fn7} that takes the first two arguments as a {@link Product2}<A, B> and the * remaining arguments. * - * @return an {@link Fn7} taking a {@link Tuple2} and the remaining arguments + * @return an {@link Fn7} taking a {@link Product2} and the remaining arguments */ @Override - default Fn7, C, D, E, F, G, H, I> uncurry() { + default Fn7, C, D, E, F, G, H, I> uncurry() { return (ab, c, d, e, f, g, h) -> apply(ab._1(), ab._2(), c, d, e, f, g, h); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java index c3c8381ed..dc853a3f3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java @@ -1,20 +1,20 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import java.util.function.BiFunction; /** - * Given a {@link BiFunction}<A, B, C> and a {@link Tuple2}<A, B>, destructure the - * tuple and apply the slots as arguments to the function, returning the result. + * Given a {@link BiFunction}<A, B, C> and a {@link Product2}<A, B>, destructure + * the product and apply the slots as arguments to the function, returning the result. * * @param the first argument type * @param the second argument type * @param the result type */ -public final class Into implements Fn2, Tuple2, C> { +public final class Into implements Fn2, Product2, C> { private static final Into INSTANCE = new Into(); @@ -22,8 +22,8 @@ private Into() { } @Override - public C apply(BiFunction fn, Tuple2 tuple) { - return tuple.into(fn); + public C apply(BiFunction fn, Product2 product) { + return product.into(fn); } @SuppressWarnings("unchecked") @@ -31,11 +31,13 @@ public static Into into() { return INSTANCE; } - public static Fn1, C> into(BiFunction fn) { + public static Fn1, C> into( + BiFunction fn) { return Into.into().apply(fn); } - public static C into(BiFunction fn, Tuple2 tuple) { - return Into.into(fn).apply(tuple); + public static C into(BiFunction fn, + Product2 product) { + return Into.into(fn).apply(product); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java index 1ab7e302e..9572d3f8d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java @@ -1,26 +1,26 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; -import com.jnape.palatable.lambda.adt.hlist.Tuple3; +import com.jnape.palatable.lambda.adt.product.Product3; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; /** - * Given an {@link Fn3}<A, B, C, D> and a {@link Tuple3}<A, B, C>, destructure the - * tuple and apply the slots as arguments to the function, returning the result. + * Given an {@link Fn3}<A, B, C, D> and a {@link Product3}<A, B, C>, destructure + * the product and apply the slots as arguments to the function, returning the result. * * @param the first argument type * @param the second argument type * @param the third argument type * @param the result type */ -public final class Into3 implements Fn2, Tuple3, D> { +public final class Into3 implements Fn2, Product3, D> { private static final Into3 INSTANCE = new Into3(); @Override - public D apply(Fn3 fn, Tuple3 tuple) { - return tuple.into(fn); + public D apply(Fn3 fn, Product3 product) { + return product.into(fn); } @SuppressWarnings("unchecked") @@ -28,11 +28,12 @@ public static Into3 into3() { return INSTANCE; } - public static Fn1, D> into3(Fn3 fn) { + public static Fn1, D> into3(Fn3 fn) { return Into3.into3().apply(fn); } - public static D into3(Fn3 fn, Tuple3 tuple) { - return Into3.into3(fn).apply(tuple); + public static D into3(Fn3 fn, + Product3 product) { + return Into3.into3(fn).apply(product); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java index 991495fc5..9cd0f37e0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java @@ -1,13 +1,13 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; -import com.jnape.palatable.lambda.adt.hlist.Tuple4; +import com.jnape.palatable.lambda.adt.product.Product4; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn4; /** - * Given an {@link Fn4}<A, B, C, D, E> and a {@link Tuple4}<A, B, C, D>, - * destructure the tuple and apply the slots as arguments to the function, returning the result. + * Given an {@link Fn4}<A, B, C, D, E> and a {@link Product4}<A, B, C, D>, + * destructure the product and apply the slots as arguments to the function, returning the result. * * @param the first argument type * @param the second argument type @@ -15,13 +15,13 @@ * @param the fourth argument type * @param the result type */ -public final class Into4 implements Fn2, Tuple4, E> { +public final class Into4 implements Fn2, Product4, E> { private static final Into4 INSTANCE = new Into4(); @Override - public E apply(Fn4 fn, Tuple4 tuple) { - return tuple.into(fn); + public E apply(Fn4 fn, Product4 product) { + return product.into(fn); } @SuppressWarnings("unchecked") @@ -29,13 +29,13 @@ public static Into4 into4() { return INSTANCE; } - public static Fn1, E> into4( + public static Fn1, E> into4( Fn4 fn) { return Into4.into4().apply(fn); } public static E into4(Fn4 fn, - Tuple4 tuple) { - return Into4.into4(fn).apply(tuple); + Product4 product) { + return Into4.into4(fn).apply(product); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java index d43e64997..a55294f10 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java @@ -1,13 +1,13 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; -import com.jnape.palatable.lambda.adt.hlist.Tuple5; +import com.jnape.palatable.lambda.adt.product.Product5; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn5; /** - * Given an {@link Fn5}<A, B, C, D, E, F> and a {@link Tuple5}<A, B, C, D, E>, - * destructure the tuple and apply the slots as arguments to the function, returning the result. + * Given an {@link Fn5}<A, B, C, D, E, F> and a {@link Product5}<A, B, C, D, E>, + * destructure the product and apply the slots as arguments to the function, returning the result. * * @param the first argument type * @param the second argument type @@ -16,14 +16,14 @@ * @param the fifth argument type * @param the result type */ -public final class Into5 implements Fn2, Tuple5, F> { +public final class Into5 implements Fn2, Product5, F> { private static final Into5 INSTANCE = new Into5(); @Override public F apply(Fn5 fn, - Tuple5 tuple) { - return tuple.into(fn); + Product5 product) { + return product.into(fn); } @SuppressWarnings("unchecked") @@ -31,13 +31,13 @@ public static Into5 into5() { return INSTANCE; } - public static Fn1, F> into5( + public static Fn1, F> into5( Fn5 fn) { return Into5.into5().apply(fn); } public static F into5(Fn5 fn, - Tuple5 tuple) { - return Into5.into5(fn).apply(tuple); + Product5 product) { + return Into5.into5(fn).apply(product); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java index 9ac76cc26..9caf25a5b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java @@ -1,14 +1,14 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; -import com.jnape.palatable.lambda.adt.hlist.Tuple6; +import com.jnape.palatable.lambda.adt.product.Product6; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn6; /** * Given an {@link Fn6}<A, B, C, D, E, F, G> and a - * {@link Tuple6}<A, B, C, D, E, F>, destructure the tuple and apply the slots as arguments to the - * function, returning the result. + * {@link Product6}<A, B, C, D, E, F>, destructure the product and apply the slots as arguments to + * the function, returning the result. * * @param the first argument type * @param the second argument type @@ -18,14 +18,14 @@ * @param the sixth argument type * @param the result type */ -public final class Into6 implements Fn2, Tuple6, G> { +public final class Into6 implements Fn2, Product6, G> { private static final Into6 INSTANCE = new Into6(); @Override public G apply(Fn6 fn, - Tuple6 tuple) { - return tuple.into(fn); + Product6 product) { + return product.into(fn); } @SuppressWarnings("unchecked") @@ -33,14 +33,14 @@ public static Into6 into6() { return INSTANCE; } - public static Fn1, G> into6( + public static Fn1, G> into6( Fn6 fn) { return Into6.into6().apply(fn); } public static G into6( Fn6 fn, - Tuple6 tuple) { - return Into6.into6(fn).apply(tuple); + Product6 product) { + return Into6.into6(fn).apply(product); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java index 6831e54ae..3ea4d0ebd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java @@ -1,14 +1,14 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; -import com.jnape.palatable.lambda.adt.hlist.Tuple7; +import com.jnape.palatable.lambda.adt.product.Product7; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn7; /** * Given an {@link Fn7}<A, B, C, D, E, F, G, H> and a - * {@link Tuple7}<A, B, C, D, E, F, G>, destructure the tuple and apply the slots as arguments to the - * function, returning the result. + * {@link Product7}<A, B, C, D, E, F, G>, destructure the product and apply the slots as arguments to + * the function, returning the result. * * @param the first argument type * @param the second argument type @@ -19,14 +19,14 @@ * @param the seventh argument type * @param the result type */ -public final class Into7 implements Fn2, Tuple7, H> { +public final class Into7 implements Fn2, Product7, H> { private static final Into7 INSTANCE = new Into7(); @Override public H apply(Fn7 fn, - Tuple7 tuple) { - return tuple.into(fn); + Product7 product) { + return product.into(fn); } @SuppressWarnings("unchecked") @@ -34,14 +34,14 @@ public static Into7 into7() { return INSTANCE; } - public static Fn1, H> into7( + public static Fn1, H> into7( Fn7 fn) { return Into7.into7().apply(fn); } public static H into7( Fn7 fn, - Tuple7 tuple) { - return Into7.into7(fn).apply(tuple); + Product7 product) { + return Into7.into7(fn).apply(product); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java index 6a214ccf0..a04d17660 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java @@ -1,14 +1,14 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; -import com.jnape.palatable.lambda.adt.hlist.Tuple8; +import com.jnape.palatable.lambda.adt.product.Product8; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn8; /** * Given an {@link Fn8}<A, B, C, D, E, F, G, H, I> and a - * {@link Tuple8}<A, B, C, D, E, F, G, H>, destructure the tuple and apply the slots as arguments to - * the function, returning the result. + * {@link Product8}<A, B, C, D, E, F, G, H>, destructure the product and apply the slots as arguments + * to the function, returning the result. * * @param the first argument type * @param the second argument type @@ -20,15 +20,15 @@ * @param the eighth argument type * @param the result type */ -public final class Into8 implements Fn2, Tuple8, I> { +public final class Into8 implements Fn2, Product8, I> { private static final Into8 INSTANCE = new Into8(); @Override public I apply( Fn8 fn, - Tuple8 tuple) { - return tuple.into(fn); + Product8 product) { + return product.into(fn); } @SuppressWarnings("unchecked") @@ -36,14 +36,14 @@ public static Into8 into8 return INSTANCE; } - public static Fn1, I> into8( + public static Fn1, I> into8( Fn8 fn) { return Into8.into8().apply(fn); } public static I into8( Fn8 fn, - Tuple8 tuple) { - return Into8.into8(fn).apply(tuple); + Product8 product) { + return Into8.into8(fn).apply(product); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java index fee6e7339..352de9585 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions.specialized; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.monoid.Monoid; @FunctionalInterface @@ -20,7 +20,7 @@ default BiMonoidFactory flip() { } @Override - default MonoidFactory, C> uncurry() { + default MonoidFactory, C> uncurry() { return ab -> apply(ab._1()).apply(ab._2()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java index b7fe21c35..8d28fb290 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions.specialized; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn2; import java.util.function.Function; @@ -43,7 +43,7 @@ default BiPredicate flip() { * {@inheritDoc} */ @Override - default Predicate> uncurry() { + default Predicate> uncurry() { return Fn2.super.uncurry()::apply; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java index d7266132c..a2a16d899 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functions.specialized; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn4; import com.jnape.palatable.lambda.semigroup.Semigroup; @@ -21,7 +21,7 @@ default BiSemigroupFactory flip() { } @Override - default SemigroupFactory, C> uncurry() { + default SemigroupFactory, C> uncurry() { return ab -> apply(ab._1(), ab._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 9d8d9a0d2..ab8396fd3 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,6 +1,7 @@ package com.jnape.palatable.lambda.functions.recursion; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import org.junit.Test; import java.math.BigInteger; @@ -16,7 +17,7 @@ public class TrampolineTest { - private static final Function, RecursiveResult, BigInteger>> FACTORIAL = + private static final Function, RecursiveResult, BigInteger>> FACTORIAL = into((x, acc) -> x.compareTo(ONE) > 0 ? recurse(tuple(x.subtract(ONE), x.multiply(acc))) : terminate(acc)); @Test From fb18ccf72173abfba3fabd1e09361358d9cd8b9c Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 20 May 2018 17:42:51 -0500 Subject: [PATCH 036/348] coproducts now all project into general products --- CHANGELOG.md | 1 + .../lambda/adt/coproduct/CoProduct2.java | 14 +++++------ .../lambda/adt/coproduct/CoProduct3.java | 14 +++++------ .../lambda/adt/coproduct/CoProduct4.java | 16 ++++++------- .../lambda/adt/coproduct/CoProduct5.java | 18 +++++++------- .../lambda/adt/coproduct/CoProduct6.java | 20 ++++++++-------- .../lambda/adt/coproduct/CoProduct7.java | 22 ++++++++--------- .../lambda/adt/coproduct/CoProduct8.java | 24 +++++++++---------- 8 files changed, 65 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e67068a2d..4ca959c33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `TypeSafeKey.Simple` now has a default `#apply` implementation - `Tuple2-8` now implement `Product2-8` - `Into2-8` now accepts a product of the same cardinality, instead of requiring a tuple +- `CoProduct2-8#project` now return generalized products ### Fixed - mapped `TypeSafeKey` instances can be used for initial put in an `HMap`, and the base key can be used to retrieve them diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java index 5aadd08a0..6c2c43ee8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice2; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; import java.util.function.Function; @@ -70,18 +70,18 @@ public R match(Function aFn, Function, Maybe> project() { + default Product2, Maybe> project() { return match(a -> tuple(just(a), nothing()), b -> tuple(nothing(), just(b))); } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the first slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the first slot value. * * @return an optional value representing the projection of the "a" type index */ @@ -90,7 +90,7 @@ default Maybe projectA() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the second slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the second slot value. * * @return an optional value representing the projection of the "b" type index */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java index 6937d4735..967e950e2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.adt.hlist.Tuple3; +import com.jnape.palatable.lambda.adt.product.Product3; import com.jnape.palatable.lambda.functions.Fn1; import java.util.function.Function; @@ -82,19 +82,19 @@ public R match(Function aFn, Function, Maybe, Maybe> project() { + default Product3, Maybe, Maybe> project() { return match(a -> tuple(just(a), nothing(), nothing()), b -> tuple(nothing(), just(b), nothing()), c -> tuple(nothing(), nothing(), just(c))); } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the first slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the first slot value. * * @return an optional value representing the projection of the "a" type index */ @@ -103,7 +103,7 @@ default Maybe projectA() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the second slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the second slot value. * * @return an optional value representing the projection of the "b" type index */ @@ -112,7 +112,7 @@ default Maybe projectB() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the third slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the third slot value. * * @return an optional value representing the projection of the "c" type index */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java index 96939fba9..cc4f47b57 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.adt.hlist.Tuple4; +import com.jnape.palatable.lambda.adt.product.Product4; import com.jnape.palatable.lambda.functions.Fn1; import java.util.function.Function; @@ -90,12 +90,12 @@ public R match(Function aFn, Function, Maybe, Maybe, Maybe> project() { + default Product4, Maybe, Maybe, Maybe> project() { return match(a -> tuple(just(a), nothing(), nothing(), nothing()), b -> tuple(nothing(), just(b), nothing(), nothing()), c -> tuple(nothing(), nothing(), just(c), nothing()), @@ -103,7 +103,7 @@ default Tuple4, Maybe, Maybe, Maybe> project() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the first slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the first slot value. * * @return an optional value representing the projection of the "a" type index */ @@ -112,7 +112,7 @@ default Maybe projectA() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the second slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the second slot value. * * @return an optional value representing the projection of the "b" type index */ @@ -121,7 +121,7 @@ default Maybe projectB() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the third slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the third slot value. * * @return an optional value representing the projection of the "c" type index */ @@ -130,7 +130,7 @@ default Maybe projectC() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the fourth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the fourth slot value. * * @return an optional value representing the projection of the "d" type index */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java index ffaf5ef1b..aa64d58c0 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.adt.hlist.Tuple5; +import com.jnape.palatable.lambda.adt.product.Product5; import com.jnape.palatable.lambda.functions.Fn1; import java.util.function.Function; @@ -98,12 +98,12 @@ public R match(Function aFn, Function, Maybe, Maybe, Maybe, Maybe> project() { + default Product5, Maybe, Maybe, Maybe, Maybe> project() { return match(a -> tuple(just(a), nothing(), nothing(), nothing(), nothing()), b -> tuple(nothing(), just(b), nothing(), nothing(), nothing()), c -> tuple(nothing(), nothing(), just(c), nothing(), nothing()), @@ -112,7 +112,7 @@ default Tuple5, Maybe, Maybe, Maybe, Maybe> project() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the first slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the first slot value. * * @return an optional value representing the projection of the "a" type index */ @@ -121,7 +121,7 @@ default Maybe projectA() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the second slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the second slot value. * * @return an optional value representing the projection of the "b" type index */ @@ -130,7 +130,7 @@ default Maybe projectB() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the third slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the third slot value. * * @return an optional value representing the projection of the "c" type index */ @@ -139,7 +139,7 @@ default Maybe projectC() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the fourth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the fourth slot value. * * @return an optional value representing the projection of the "d" type index */ @@ -148,7 +148,7 @@ default Maybe projectD() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the fifth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the fifth slot value. * * @return an optional value representing the projection of the "e" type index */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java index 947036ce1..2ff159c7b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice5; -import com.jnape.palatable.lambda.adt.hlist.Tuple6; +import com.jnape.palatable.lambda.adt.product.Product6; import com.jnape.palatable.lambda.functions.Fn1; import java.util.function.Function; @@ -79,12 +79,12 @@ public R match(Function aFn, Function, Maybe, Maybe, Maybe, Maybe, Maybe> project() { + default Product6, Maybe, Maybe, Maybe, Maybe, Maybe> project() { return match(a -> tuple(just(a), nothing(), nothing(), nothing(), nothing(), nothing()), b -> tuple(nothing(), just(b), nothing(), nothing(), nothing(), nothing()), c -> tuple(nothing(), nothing(), just(c), nothing(), nothing(), nothing()), @@ -94,7 +94,7 @@ default Tuple6, Maybe, Maybe, Maybe, Maybe, Maybe> proje } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the first slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the first slot value. * * @return an optional value representing the projection of the "a" type index */ @@ -103,7 +103,7 @@ default Maybe projectA() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the second slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the second slot value. * * @return an optional value representing the projection of the "b" type index */ @@ -112,7 +112,7 @@ default Maybe projectB() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the third slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the third slot value. * * @return an optional value representing the projection of the "c" type index */ @@ -121,7 +121,7 @@ default Maybe projectC() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the fourth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the fourth slot value. * * @return an optional value representing the projection of the "d" type index */ @@ -130,7 +130,7 @@ default Maybe projectD() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the fifth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the fifth slot value. * * @return an optional value representing the projection of the "e" type index */ @@ -139,7 +139,7 @@ default Maybe projectE() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the sixth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the sixth slot value. * * @return an optional value representing the projection of the "f" type index */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java index 3b57fce9b..6c8444204 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice6; -import com.jnape.palatable.lambda.adt.hlist.Tuple7; +import com.jnape.palatable.lambda.adt.product.Product7; import com.jnape.palatable.lambda.functions.Fn1; import java.util.function.Function; @@ -82,12 +82,12 @@ public R match(Function aFn, Function, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe> project() { + default Product7, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe> project() { return match(a -> tuple(just(a), nothing(), nothing(), nothing(), nothing(), nothing(), nothing()), b -> tuple(nothing(), just(b), nothing(), nothing(), nothing(), nothing(), nothing()), c -> tuple(nothing(), nothing(), just(c), nothing(), nothing(), nothing(), nothing()), @@ -98,7 +98,7 @@ default Tuple7, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the first slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the first slot value. * * @return an optional value representing the projection of the "a" type index */ @@ -107,7 +107,7 @@ default Maybe projectA() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the second slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the second slot value. * * @return an optional value representing the projection of the "b" type index */ @@ -116,7 +116,7 @@ default Maybe projectB() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the third slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the third slot value. * * @return an optional value representing the projection of the "c" type index */ @@ -125,7 +125,7 @@ default Maybe projectC() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the fourth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the fourth slot value. * * @return an optional value representing the projection of the "d" type index */ @@ -134,7 +134,7 @@ default Maybe projectD() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the fifth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the fifth slot value. * * @return an optional value representing the projection of the "e" type index */ @@ -143,7 +143,7 @@ default Maybe projectE() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the sixth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the sixth slot value. * * @return an optional value representing the projection of the "f" type index */ @@ -152,7 +152,7 @@ default Maybe projectF() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the seventh slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the seventh slot value. * * @return an optional value representing the projection of the "g" type index */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java index 3a55b2c24..a94ab4586 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.choice.Choice7; -import com.jnape.palatable.lambda.adt.hlist.Tuple8; +import com.jnape.palatable.lambda.adt.product.Product8; import com.jnape.palatable.lambda.functions.Fn1; import java.util.function.Function; @@ -66,12 +66,12 @@ R match(Function aFn, } /** - * Project this coproduct onto a tuple. + * Project this coproduct onto a product. * - * @return a tuple of the coproduct projection + * @return a product of the coproduct projection * @see CoProduct2#project() */ - default Tuple8, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe> project() { + default Product8, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe> project() { return match(a -> tuple(just(a), nothing(), nothing(), nothing(), nothing(), nothing(), nothing(), nothing()), b -> tuple(nothing(), just(b), nothing(), nothing(), nothing(), nothing(), nothing(), nothing()), c -> tuple(nothing(), nothing(), just(c), nothing(), nothing(), nothing(), nothing(), nothing()), @@ -83,7 +83,7 @@ default Tuple8, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the first slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the first slot value. * * @return an optional value representing the projection of the "a" type index */ @@ -92,7 +92,7 @@ default Maybe projectA() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the second slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the second slot value. * * @return an optional value representing the projection of the "b" type index */ @@ -101,7 +101,7 @@ default Maybe projectB() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the third slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the third slot value. * * @return an optional value representing the projection of the "c" type index */ @@ -110,7 +110,7 @@ default Maybe projectC() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the fourth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the fourth slot value. * * @return an optional value representing the projection of the "d" type index */ @@ -119,7 +119,7 @@ default Maybe projectD() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the fifth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the fifth slot value. * * @return an optional value representing the projection of the "e" type index */ @@ -128,7 +128,7 @@ default Maybe projectE() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the sixth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the sixth slot value. * * @return an optional value representing the projection of the "f" type index */ @@ -137,7 +137,7 @@ default Maybe projectF() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the seventh slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the seventh slot value. * * @return an optional value representing the projection of the "g" type index */ @@ -146,7 +146,7 @@ default Maybe projectG() { } /** - * Convenience method for projecting this coproduct onto a tuple and then extracting the eighth slot value. + * Convenience method for projecting this coproduct onto a product and then extracting the eighth slot value. * * @return an optional value representing the projection of the "h" type index */ From d2d3ce519367de673b94b3916521f3a93ea45f10 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 20 May 2018 17:38:18 -0500 Subject: [PATCH 037/348] Fn1#uncurry and into* variants now accept general products --- CHANGELOG.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ca959c33..44e0618d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - Adding composition guarantees to `LensLike` - `CmpEqBy`, `CmpEq`, `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` inequality checks - `MinBy`, `MaxBy`, `Min`, and `Max` semigroups +- `Product2-8` interfaces, representing general product types + +### Changed +- `Tuple2-8` now implement `Product2-8` +- `Into2-8` now accepts a product of the same cardinality, instead of requiring a tuple +- `CoProduct2-8#project` now return generalized products ## [3.0.3] - 2018-05-27 ### Added @@ -22,13 +28,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [3.0.2] - 2018-05-21 ### Added - `IterableLens#mapping`, an `Iso` that maps values -- `Product2-8` interfaces, representing general product types ### Changed - `TypeSafeKey.Simple` now has a default `#apply` implementation -- `Tuple2-8` now implement `Product2-8` -- `Into2-8` now accepts a product of the same cardinality, instead of requiring a tuple -- `CoProduct2-8#project` now return generalized products ### Fixed - mapped `TypeSafeKey` instances can be used for initial put in an `HMap`, and the base key can be used to retrieve them From b600ab7881cf0f605ac4a8f8e7e386cdc5568a69 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 3 Jun 2018 16:12:02 -0500 Subject: [PATCH 038/348] Choice2-8 return tuples --- CHANGELOG.md | 1 + .../palatable/lambda/adt/choice/Choice2.java | 21 ++++++++++++++++++- .../palatable/lambda/adt/choice/Choice3.java | 15 +++++++++++++ .../palatable/lambda/adt/choice/Choice4.java | 15 +++++++++++++ .../palatable/lambda/adt/choice/Choice5.java | 15 +++++++++++++ .../palatable/lambda/adt/choice/Choice6.java | 15 +++++++++++++ .../palatable/lambda/adt/choice/Choice7.java | 15 +++++++++++++ .../palatable/lambda/adt/choice/Choice8.java | 15 +++++++++++++ 8 files changed, 111 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44e0618d8..02b2362c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Tuple2-8` now implement `Product2-8` - `Into2-8` now accepts a product of the same cardinality, instead of requiring a tuple - `CoProduct2-8#project` now return generalized products +- `Choice2-8#project` return tuples ## [3.0.3] - 2018-05-27 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index 5276adb04..969da832d 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -1,7 +1,10 @@ package com.jnape.palatable.lambda.adt.choice; import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -10,6 +13,8 @@ import java.util.Objects; import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; + /** * Canonical ADT representation of {@link CoProduct2}. Unlike {@link Either}, there is no concept of "success" or * "failure", so the domain of reasonable function semantics is more limited. @@ -19,11 +24,25 @@ * @see Either * @see Choice3 */ -public abstract class Choice2 implements CoProduct2>, Monad>, Bifunctor, Traversable> { +public abstract class Choice2 implements + CoProduct2>, + Monad>, + Bifunctor, + Traversable> { private Choice2() { } + /** + * Specialize this choice's projection to a {@link Tuple2}. + * + * @return a {@link Tuple2} + */ + @Override + public Tuple2, Maybe> project() { + return into(HList::tuple, CoProduct2.super.project()); + } + @Override public final Choice3 diverge() { return match(Choice3::a, Choice3::b); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 8cc0abba5..1f8aa3226 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -1,7 +1,10 @@ package com.jnape.palatable.lambda.adt.choice; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.coproduct.CoProduct3; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple3; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -10,6 +13,8 @@ import java.util.Objects; import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into3.into3; + /** * Canonical ADT representation of {@link CoProduct3}. * @@ -28,6 +33,16 @@ public abstract class Choice3 implements private Choice3() { } + /** + * Specialize this choice's projection to a {@link Tuple3}. + * + * @return a {@link Tuple3} + */ + @Override + public Tuple3, Maybe, Maybe> project() { + return into3(HList::tuple, CoProduct3.super.project()); + } + @Override public final Choice4 diverge() { return match(Choice4::a, Choice4::b, Choice4::c); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index 9a604fa71..494638330 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -1,7 +1,10 @@ package com.jnape.palatable.lambda.adt.choice; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.coproduct.CoProduct3; import com.jnape.palatable.lambda.adt.coproduct.CoProduct4; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple4; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -10,6 +13,8 @@ import java.util.Objects; import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into4.into4; + /** * Canonical ADT representation of {@link CoProduct4}. * @@ -29,6 +34,16 @@ public abstract class Choice4 implements private Choice4() { } + /** + * Specialize this choice's projection to a {@link Tuple4}. + * + * @return a {@link Tuple4} + */ + @Override + public Tuple4, Maybe, Maybe, Maybe> project() { + return into4(HList::tuple, CoProduct4.super.project()); + } + @Override public Choice5 diverge() { return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index 758aa2a00..5954d4ae2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -1,7 +1,10 @@ package com.jnape.palatable.lambda.adt.choice; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.coproduct.CoProduct4; import com.jnape.palatable.lambda.adt.coproduct.CoProduct5; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple5; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -10,6 +13,8 @@ import java.util.Objects; import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into5.into5; + /** * Canonical ADT representation of {@link CoProduct5}. * @@ -30,6 +35,16 @@ public abstract class Choice5 implements private Choice5() { } + /** + * Specialize this choice's projection to a {@link Tuple5}. + * + * @return a {@link Tuple5} + */ + @Override + public Tuple5, Maybe, Maybe, Maybe, Maybe> project() { + return into5(HList::tuple, CoProduct5.super.project()); + } + @Override public Choice6 diverge() { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index 9286e9abf..8076383b8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -1,7 +1,10 @@ package com.jnape.palatable.lambda.adt.choice; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.coproduct.CoProduct5; import com.jnape.palatable.lambda.adt.coproduct.CoProduct6; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple6; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -10,6 +13,8 @@ import java.util.Objects; import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into6.into6; + /** * Canonical ADT representation of {@link CoProduct6}. * @@ -31,6 +36,16 @@ public abstract class Choice6 implements private Choice6() { } + /** + * Specialize this choice's projection to a {@link Tuple6}. + * + * @return a {@link Tuple6} + */ + @Override + public Tuple6, Maybe, Maybe, Maybe, Maybe, Maybe> project() { + return into6(HList::tuple, CoProduct6.super.project()); + } + @Override public Choice7 diverge() { return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index 18d9bdc9e..bd7f3b65f 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -1,7 +1,10 @@ package com.jnape.palatable.lambda.adt.choice; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.coproduct.CoProduct6; import com.jnape.palatable.lambda.adt.coproduct.CoProduct7; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple7; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -10,6 +13,8 @@ import java.util.Objects; import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into7.into7; + /** * Canonical ADT representation of {@link CoProduct7}. * @@ -32,6 +37,16 @@ public abstract class Choice7 implements private Choice7() { } + /** + * Specialize this choice's projection to a {@link Tuple7}. + * + * @return a {@link Tuple7} + */ + @Override + public Tuple7, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe> project() { + return into7(HList::tuple, CoProduct7.super.project()); + } + @Override public Choice8 diverge() { return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, Choice8::g); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index e7ec41a49..9755c5050 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -1,7 +1,10 @@ package com.jnape.palatable.lambda.adt.choice; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.coproduct.CoProduct7; import com.jnape.palatable.lambda.adt.coproduct.CoProduct8; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple8; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -10,6 +13,8 @@ import java.util.Objects; import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into8.into8; + /** * Canonical ADT representation of {@link CoProduct8}. * @@ -32,6 +37,16 @@ public abstract class Choice8 implements private Choice8() { } + /** + * Specialize this choice's projection to a {@link Tuple8}. + * + * @return a {@link Tuple8} + */ + @Override + public Tuple8, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe> project() { + return into8(HList::tuple, CoProduct8.super.project()); + } + @Override public Choice7 converge( Function> convergenceFn) { From 77f8e02d289d893a5883fde2f98b8ed4998abdce Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 10 Jun 2018 16:14:02 -0500 Subject: [PATCH 039/348] Union --- CHANGELOG.md | 1 + .../lambda/monoid/builtin/Union.java | 47 +++++++++++++++++++ .../lambda/monoid/builtin/UnionTest.java | 44 +++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monoid/builtin/UnionTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 02b2362c0..3eee72a1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `CmpEqBy`, `CmpEq`, `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` inequality checks - `MinBy`, `MaxBy`, `Min`, and `Max` semigroups - `Product2-8` interfaces, representing general product types +- `Union`, a semigroup that behaves like a lazy set union on `Iterable`s ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java new file mode 100644 index 000000000..1489195be --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java @@ -0,0 +1,47 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.monoid.Monoid; + +import java.util.Collections; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; +import static com.jnape.palatable.lambda.monoid.builtin.Concat.concat; + +/** + * Given two {@link Iterable}s, return the union of all unique occurrences of elements between them. Note that this + * operation preserves order, so the unique elements of the first {@link Iterable} are iterated before the unique + * elements of the second {@link Iterable}. + * + * @param the {@link Iterable} element type) + */ +public final class Union implements Monoid> { + + private static final Union INSTANCE = new Union(); + + private Union() { + } + + @Override + public Iterable identity() { + return Collections::emptyIterator; + } + + @Override + public Iterable apply(Iterable xs, Iterable ys) { + return distinct(concat(xs, ys)); + } + + @SuppressWarnings("unchecked") + public static Union union() { + return INSTANCE; + } + + public static Fn1, Iterable> union(Iterable xs) { + return Union.union().apply(xs); + } + + public static Iterable union(Iterable xs, Iterable ys) { + return union(xs).apply(ys); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/UnionTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/UnionTest.java new file mode 100644 index 000000000..092bf9414 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/UnionTest.java @@ -0,0 +1,44 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.EmptyIterableSupport; +import testsupport.traits.FiniteIteration; +import testsupport.traits.ImmutableIteration; +import testsupport.traits.InfiniteIterableSupport; +import testsupport.traits.Laziness; + +import static com.jnape.palatable.lambda.monoid.builtin.Union.union; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IterableMatcher.isEmpty; +import static testsupport.matchers.IterableMatcher.iterates; + +@RunWith(Traits.class) +public class UnionTest { + + @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) + public Fn1, Iterable> testSubject() { + return union(asList(1, 2, 3)); + } + + @Test + public void identity() { + assertThat(union().identity(), isEmpty()); + } + + @Test + public void semigroup() { + assertThat(union(emptyList(), emptyList()), isEmpty()); + assertThat(union(asList(1, 2), emptyList()), iterates(1, 2)); + assertThat(union(emptyList(), singletonList(3)), iterates(3)); + assertThat(union(asList(1, 2), singletonList(3)), iterates(1, 2, 3)); + assertThat(union(asList(1, 2, 2), singletonList(3)), iterates(1, 2, 3)); + assertThat(union(asList(1, 2), asList(1, 2, 3)), iterates(1, 2, 3)); + } +} \ No newline at end of file From ed6dac74ac2a9e4e004ffc7d14f50e180c81d642 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 10 Jun 2018 16:18:39 -0500 Subject: [PATCH 040/348] Adding missing final keywords --- src/main/java/com/jnape/palatable/lambda/adt/hmap/HMap.java | 2 +- .../jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java | 2 +- .../com/jnape/palatable/lambda/functor/builtin/Compose.java | 2 +- .../jnape/palatable/lambda/iteration/CombinatorialIterator.java | 2 +- .../com/jnape/palatable/lambda/iteration/CyclicIterator.java | 2 +- .../com/jnape/palatable/lambda/iteration/DroppingIterator.java | 2 +- .../com/jnape/palatable/lambda/iteration/FilteringIterator.java | 2 +- .../com/jnape/palatable/lambda/iteration/GroupingIterator.java | 2 +- .../java/com/jnape/palatable/lambda/iteration/InitIterator.java | 2 +- .../com/jnape/palatable/lambda/iteration/MappingIterator.java | 2 +- .../palatable/lambda/iteration/PredicatedDroppingIterator.java | 2 +- .../palatable/lambda/iteration/PredicatedTakingIterator.java | 2 +- .../jnape/palatable/lambda/iteration/RepetitiousIterator.java | 2 +- .../com/jnape/palatable/lambda/iteration/ReversingIterator.java | 2 +- .../jnape/palatable/lambda/iteration/RewindableIterator.java | 2 +- .../com/jnape/palatable/lambda/iteration/TakingIterator.java | 2 +- .../com/jnape/palatable/lambda/iteration/UnfoldingIterator.java | 2 +- .../com/jnape/palatable/lambda/iteration/ZippingIterator.java | 2 +- .../java/com/jnape/palatable/lambda/monoid/builtin/And.java | 2 +- .../java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java | 2 +- src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java | 2 +- .../java/com/jnape/palatable/lambda/monoid/builtin/Xor.java | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) 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 21de6c983..df5cf50d7 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 @@ -27,7 +27,7 @@ * @see TypeSafeKey * @see com.jnape.palatable.lambda.adt.hlist.HList */ -public class HMap implements Iterable> { +public final class HMap implements Iterable> { private static final HMap EMPTY = new HMap(emptyMap()); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java index e2ba773e5..1ef163a74 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java @@ -20,7 +20,7 @@ * @param the Map value type * @see InGroupsOf */ -public class GroupBy implements Fn2, Iterable, Map>> { +public final class GroupBy implements Fn2, Iterable, Map>> { private static final GroupBy INSTANCE = new GroupBy(); diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index 568988a9d..4c4b2435f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -13,7 +13,7 @@ * @param The inner applicative * @param The carrier type */ -public class Compose implements Applicative> { +public final class Compose implements Applicative> { private final Applicative, F> fga; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java index 1aefe0536..219582f4a 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java @@ -8,7 +8,7 @@ import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -public class CombinatorialIterator extends ImmutableIterator> { +public final class CombinatorialIterator extends ImmutableIterator> { private final Iterator asIterator; private final Iterator bsIterator; private final ListIterator doublyLinkedBsIterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java index ba04f23b8..2705ffa06 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java @@ -4,7 +4,7 @@ import java.util.Iterator; import java.util.ListIterator; -public class CyclicIterator extends InfiniteIterator { +public final class CyclicIterator extends InfiniteIterator { private final Iterator iterator; private final ListIterator doublyLinkedIterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java index e0c543c3f..5f69eb643 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java @@ -3,7 +3,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; -public class DroppingIterator extends ImmutableIterator { +public final class DroppingIterator extends ImmutableIterator { private final Integer n; private final Iterator asIterator; private boolean dropped; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java index 75f02db95..cde34d842 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java @@ -4,7 +4,7 @@ import java.util.NoSuchElementException; import java.util.function.Function; -public class FilteringIterator extends ImmutableIterator { +public final class FilteringIterator extends ImmutableIterator { private final Function predicate; private final RewindableIterator rewindableIterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java index 6960c87c8..fdaf95ebe 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java @@ -4,7 +4,7 @@ import java.util.Iterator; import java.util.List; -public class GroupingIterator extends ImmutableIterator> { +public final class GroupingIterator extends ImmutableIterator> { private final Integer k; private final Iterator asIterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java index e89ebf1fb..0b1daa4e9 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java @@ -3,7 +3,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; -public class InitIterator extends ImmutableIterator { +public final class InitIterator extends ImmutableIterator { private final Iterator asIterator; private A queued; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java index 82624603f..0d336fa89 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java @@ -3,7 +3,7 @@ import java.util.Iterator; import java.util.function.Function; -public class MappingIterator extends ImmutableIterator { +public final class MappingIterator extends ImmutableIterator { private final Function function; private final Iterator iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java index e94b97d5d..852ee37ed 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java @@ -4,7 +4,7 @@ import java.util.NoSuchElementException; import java.util.function.Function; -public class PredicatedDroppingIterator extends ImmutableIterator { +public final class PredicatedDroppingIterator extends ImmutableIterator { private final Function predicate; private final RewindableIterator rewindableIterator; private boolean finishedDropping; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java index a53684946..6612b50d1 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java @@ -4,7 +4,7 @@ import java.util.NoSuchElementException; import java.util.function.Function; -public class PredicatedTakingIterator extends ImmutableIterator { +public final class PredicatedTakingIterator extends ImmutableIterator { private final Function predicate; private final RewindableIterator rewindableIterator; private boolean stillTaking; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java index 7f43bed68..51a6715a5 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.iteration; -public class RepetitiousIterator extends InfiniteIterator { +public final class RepetitiousIterator extends InfiniteIterator { private final A value; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java index e676cfa11..428898058 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java @@ -4,7 +4,7 @@ import java.util.Iterator; import java.util.ListIterator; -public class ReversingIterator extends ImmutableIterator { +public final class ReversingIterator extends ImmutableIterator { private final Iterator as; private final ListIterator reversingIterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java index 07b540704..d4de2c5d7 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java @@ -3,7 +3,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; -public class RewindableIterator extends ImmutableIterator { +public final class RewindableIterator extends ImmutableIterator { private final Iterator asIterator; private final Cache cache; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java index 6cfedc82b..3b558d68e 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java @@ -3,7 +3,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; -public class TakingIterator extends ImmutableIterator { +public final class TakingIterator extends ImmutableIterator { private final int n; private final Iterator iterator; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java index 2c8790f1d..418121c7c 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java @@ -8,7 +8,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -public class UnfoldingIterator extends ImmutableIterator { +public final class UnfoldingIterator extends ImmutableIterator { private final Function>> function; private B seed; private Maybe> maybeAcc; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java index 147079e80..1b0909fd4 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java @@ -3,7 +3,7 @@ import java.util.Iterator; import java.util.function.BiFunction; -public class ZippingIterator extends ImmutableIterator { +public final class ZippingIterator extends ImmutableIterator { private final BiFunction zipper; private final Iterator asIterator; private final Iterator bsIterator; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java index 402663d91..9b4baec9b 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java @@ -14,7 +14,7 @@ * @see Or * @see Monoid */ -public class And implements Monoid, BiPredicate { +public final class And implements Monoid, BiPredicate { private static final And INSTANCE = new And(); diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java index d5fa005a6..5026328fb 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java @@ -27,7 +27,7 @@ * @see RightAll * @see Either */ -public class LeftAll implements MonoidFactory, Either> { +public final class LeftAll implements MonoidFactory, Either> { private static final LeftAll INSTANCE = new LeftAll(); diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java index 68d0813a8..951e555e6 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java @@ -13,7 +13,7 @@ * @see And * @see Monoid */ -public class Or implements Monoid, BiPredicate { +public final class Or implements Monoid, BiPredicate { private static final Or INSTANCE = new Or(); diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java index a2fe7abaf..860df1e6f 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java @@ -13,7 +13,7 @@ * @see Or * @see And */ -public class Xor implements Monoid, BiPredicate { +public final class Xor implements Monoid, BiPredicate { private static final Xor INSTANCE = new Xor(); From 8ae9df873c46985bb43f9b6de698923b14d132d5 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 10 Jun 2018 17:04:55 -0500 Subject: [PATCH 041/348] Union deforests --- .../lambda/iteration/UnioningIterable.java | 20 ++++++++++++++++ .../lambda/monoid/builtin/Union.java | 6 ++--- .../iteration/ConcatenatingIterableTest.java | 13 ---------- .../iteration/UnioningIterableTest.java | 24 +++++++++++++++++++ .../lambda/monoid/builtin/UnionTest.java | 14 +++++------ 5 files changed, 53 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java create mode 100644 src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java b/src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java new file mode 100644 index 000000000..641ab8255 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.iteration; + +import java.util.Iterator; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; + +public final class UnioningIterable implements Iterable { + + private final ConcatenatingIterable elements; + + public UnioningIterable(Iterable xs, Iterable ys) { + elements = new ConcatenatingIterable<>(xs instanceof UnioningIterable ? ((UnioningIterable) xs).elements : xs, + ys instanceof UnioningIterable ? ((UnioningIterable) ys).elements : ys); + } + + @Override + public Iterator iterator() { + return distinct(elements).iterator(); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java index 1489195be..3937d1146 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java @@ -1,13 +1,11 @@ package com.jnape.palatable.lambda.monoid.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.iteration.UnioningIterable; import com.jnape.palatable.lambda.monoid.Monoid; import java.util.Collections; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; -import static com.jnape.palatable.lambda.monoid.builtin.Concat.concat; - /** * Given two {@link Iterable}s, return the union of all unique occurrences of elements between them. Note that this * operation preserves order, so the unique elements of the first {@link Iterable} are iterated before the unique @@ -29,7 +27,7 @@ public Iterable identity() { @Override public Iterable apply(Iterable xs, Iterable ys) { - return distinct(concat(xs, ys)); + return new UnioningIterable<>(xs, ys); } @SuppressWarnings("unchecked") diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java index c9e9faf61..c82efdc70 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java @@ -1,22 +1,15 @@ package com.jnape.palatable.lambda.iteration; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.monoid.builtin.Concat; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; -import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.Deforesting; -import static com.jnape.palatable.lambda.adt.Maybe.just; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Last.last; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; import static com.jnape.palatable.traitor.framework.Subjects.subjects; -import static java.util.Arrays.asList; import static java.util.Collections.emptyList; -import static org.junit.Assert.assertEquals; @RunWith(Traits.class) public class ConcatenatingIterableTest { @@ -28,10 +21,4 @@ public Subjects, Iterable>> testSubject() { xs -> new ConcatenatingIterable<>(repeat(1), xs), xs -> new ConcatenatingIterable<>(xs, repeat(1))); } - - @Test - public void stackSafety() { - Iterable xs = Concat.concat().reduceLeft(replicate(1_000_000, asList(1, 2, 3))); - assertEquals(just(3), last(xs)); - } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java new file mode 100644 index 000000000..dddec5ad9 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java @@ -0,0 +1,24 @@ +package com.jnape.palatable.lambda.iteration; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.runner.RunWith; +import testsupport.traits.Deforesting; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static java.util.Collections.emptyList; + +@RunWith(Traits.class) +public class UnioningIterableTest { + @TestTraits({Deforesting.class}) + public Subjects, Iterable>> testSubject() { + return subjects(xs -> new UnioningIterable<>(emptyList(), xs), + xs -> new UnioningIterable<>(xs, emptyList()), + xs -> new UnioningIterable<>(repeat(1), xs), + xs -> new UnioningIterable<>(xs, repeat(1))); + } + +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/UnionTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/UnionTest.java index 092bf9414..5a423c679 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/UnionTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/UnionTest.java @@ -2,9 +2,11 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; +import testsupport.traits.Deforesting; import testsupport.traits.EmptyIterableSupport; import testsupport.traits.FiniteIteration; import testsupport.traits.ImmutableIteration; @@ -12,6 +14,7 @@ import testsupport.traits.Laziness; import static com.jnape.palatable.lambda.monoid.builtin.Union.union; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -22,18 +25,15 @@ @RunWith(Traits.class) public class UnionTest { - @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Fn1, Iterable> testSubject() { - return union(asList(1, 2, 3)); + @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class, Deforesting.class}) + public Subjects, Iterable>> testSubject() { + return subjects(union(asList(1, 2, 3)), Union.union().flip().apply(asList(1, 2, 3))); } @Test - public void identity() { + public void monoid() { assertThat(union().identity(), isEmpty()); - } - @Test - public void semigroup() { assertThat(union(emptyList(), emptyList()), isEmpty()); assertThat(union(asList(1, 2), emptyList()), iterates(1, 2)); assertThat(union(emptyList(), singletonList(3)), iterates(3)); From 8cfcc2d124946eb1342fb707ec0a4afc0600208c Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 10 Jun 2018 18:42:15 -0500 Subject: [PATCH 042/348] Difference --- CHANGELOG.md | 5 +- .../palatable/lambda/monoid/Difference.java | 53 +++++++++++++++++++ .../lambda/monoid/DifferenceTest.java | 44 +++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/monoid/Difference.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monoid/DifferenceTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eee72a1c..b6dbe51b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,11 +10,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `CmpEqBy`, `CmpEq`, `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` inequality checks - `MinBy`, `MaxBy`, `Min`, and `Max` semigroups - `Product2-8` interfaces, representing general product types -- `Union`, a semigroup that behaves like a lazy set union on `Iterable`s +- `Union`, a semigroup that behaves like a lazy set union on `Iterable`s +- `Difference`, a semigroup that behaves like a partially lazy set difference on `Iterable`s ### Changed - `Tuple2-8` now implement `Product2-8` -- `Into2-8` now accepts a product of the same cardinality, instead of requiring a tuple +- `Into2-8` now accept a product of the same cardinality, instead of requiring a tuple - `CoProduct2-8#project` now return generalized products - `Choice2-8#project` return tuples diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Difference.java b/src/main/java/com/jnape/palatable/lambda/monoid/Difference.java new file mode 100644 index 000000000..b94905a37 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/Difference.java @@ -0,0 +1,53 @@ +package com.jnape.palatable.lambda.monoid; + +import com.jnape.palatable.lambda.functions.Fn1; + +import java.util.Collections; +import java.util.HashSet; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Empty.empty; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter; +import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; + +public final class Difference implements Monoid> { + + private static final Difference INSTANCE = new Difference(); + + private Difference() { + } + + @Override + public Iterable identity() { + return Collections::emptyIterator; + } + + + @Override + public Iterable apply(Iterable xs, Iterable ys) { + return () -> { + if (empty(xs)) + return xs.iterator(); + + if (empty(ys)) + return distinct(xs).iterator(); + + //todo: pre-order dfs fold the expression tree to make stack-safe + HashSet uniqueYs = toCollection(HashSet::new, ys); + return distinct(filter(a -> !uniqueYs.contains(a), xs)).iterator(); + }; + } + + @SuppressWarnings("unchecked") + public static Difference difference() { + return INSTANCE; + } + + public static Fn1, Iterable> difference(Iterable xs) { + return Difference.difference().apply(xs); + } + + public static Iterable difference(Iterable xs, Iterable ys) { + return difference(xs).apply(ys); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/DifferenceTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/DifferenceTest.java new file mode 100644 index 000000000..66beb9cad --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monoid/DifferenceTest.java @@ -0,0 +1,44 @@ +package com.jnape.palatable.lambda.monoid; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.EmptyIterableSupport; +import testsupport.traits.FiniteIteration; +import testsupport.traits.ImmutableIteration; +import testsupport.traits.InfiniteIterableSupport; +import testsupport.traits.Laziness; + +import static com.jnape.palatable.lambda.monoid.Difference.difference; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IterableMatcher.isEmpty; +import static testsupport.matchers.IterableMatcher.iterates; + +@RunWith(Traits.class) +public class DifferenceTest { + + @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) + public Fn1, Iterable> testSubject() { + return Difference.difference().flip().apply(asList(1, 2, 3)); + } + + @Test + public void identity() { + assertThat(difference().identity(), isEmpty()); + } + + @Test + public void semigroup() { + assertThat(difference(emptyList(), emptyList()), isEmpty()); + assertThat(difference(asList(1, 2, 3), emptyList()), iterates(1, 2, 3)); + assertThat(difference(asList(1, 2, 2, 3), emptyList()), iterates(1, 2, 3)); + assertThat(difference(emptyList(), asList(1, 2, 3)), isEmpty()); + assertThat(difference(asList(1, 2, 3), singletonList(4)), iterates(1, 2, 3)); + assertThat(difference(asList(1, 2, 3), asList(2, 4)), iterates(1, 3)); + } +} \ No newline at end of file From e84c8e3ade882b10555502eb2cf6d35087bb7553 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 16 Jun 2018 17:42:05 -0500 Subject: [PATCH 043/348] Product2 implements Map.Entry, Into takes Map.Entry --- CHANGELOG.md | 3 ++- .../palatable/lambda/adt/product/Product2.java | 18 +++++++++++++++++- .../lambda/functions/builtin/fn2/Into.java | 18 +++++++++--------- .../functions/recursion/TrampolineTest.java | 4 ++-- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6dbe51b2..a6c0c0498 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - `Tuple2-8` now implement `Product2-8` -- `Into2-8` now accept a product of the same cardinality, instead of requiring a tuple +- `Into` now accepts `Map.Entry` +- `Into3-8` now accept a product of the same cardinality, instead of requiring a tuple - `CoProduct2-8#project` now return generalized products - `Choice2-8#project` return tuples diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java index bee695b01..e9619203b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import java.util.Map; import java.util.function.BiFunction; /** @@ -14,7 +15,7 @@ * @param <_2> The second element type * @see Tuple2 */ -public interface Product2<_1, _2> { +public interface Product2<_1, _2> extends Map.Entry<_1, _2> { /** * Retrieve the first element. @@ -41,4 +42,19 @@ public interface Product2<_1, _2> { default R into(BiFunction fn) { return fn.apply(_1(), _2()); } + + @Override + default _1 getKey() { + return _1(); + } + + @Override + default _2 getValue() { + return _2(); + } + + @Override + default _2 setValue(_2 value) { + throw new UnsupportedOperationException(); + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java index dc853a3f3..5fa399bb1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java @@ -1,20 +1,20 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; -import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; +import java.util.Map; import java.util.function.BiFunction; /** - * Given a {@link BiFunction}<A, B, C> and a {@link Product2}<A, B>, destructure - * the product and apply the slots as arguments to the function, returning the result. + * Given a {@link BiFunction}<A, B, C> and a {@link Map.Entry}<A, B>, destructure + * the entry and apply the key and value as arguments to the function, returning the result. * * @param the first argument type * @param the second argument type * @param the result type */ -public final class Into implements Fn2, Product2, C> { +public final class Into implements Fn2, Map.Entry, C> { private static final Into INSTANCE = new Into(); @@ -22,8 +22,8 @@ private Into() { } @Override - public C apply(BiFunction fn, Product2 product) { - return product.into(fn); + public C apply(BiFunction fn, Map.Entry entry) { + return fn.apply(entry.getKey(), entry.getValue()); } @SuppressWarnings("unchecked") @@ -31,13 +31,13 @@ public static Into into() { return INSTANCE; } - public static Fn1, C> into( + public static Fn1, C> into( BiFunction fn) { return Into.into().apply(fn); } public static C into(BiFunction fn, - Product2 product) { - return Into.into(fn).apply(product); + Map.Entry entry) { + return Into.into(fn).apply(entry); } } 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 ab8396fd3..035358e6a 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,10 +1,10 @@ package com.jnape.palatable.lambda.functions.recursion; import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.adt.product.Product2; import org.junit.Test; import java.math.BigInteger; +import java.util.Map; import java.util.function.Function; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -17,7 +17,7 @@ public class TrampolineTest { - private static final Function, RecursiveResult, BigInteger>> FACTORIAL = + private static final Function, RecursiveResult, BigInteger>> FACTORIAL = into((x, acc) -> x.compareTo(ONE) > 0 ? recurse(tuple(x.subtract(ONE), x.multiply(acc))) : terminate(acc)); @Test From 9e16ed94ba88888a263136beb02708a204edc0a7 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 16 Jun 2018 18:59:56 -0500 Subject: [PATCH 044/348] LambdaMap, lambda extension type for j.u.Map --- CHANGELOG.md | 2 + .../functions/builtin/fn2/Sequence.java | 15 +++ .../palatable/lambda/monoid/Difference.java | 1 - .../lambda/traversable/LambdaIterable.java | 17 ++-- .../lambda/traversable/LambdaMap.java | 96 +++++++++++++++++++ .../functions/builtin/fn2/SequenceTest.java | 7 ++ .../lambda/traversable/LambdaMapTest.java | 28 ++++++ 7 files changed, 154 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java create mode 100644 src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a6c0c0498..c590b71c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Product2-8` interfaces, representing general product types - `Union`, a semigroup that behaves like a lazy set union on `Iterable`s - `Difference`, a semigroup that behaves like a partially lazy set difference on `Iterable`s +- `LambdaMap`, extension point for `j.u.Map`, similar to `LambdaIterable` +- `Sequence#sequence` overloads for `j.u.Map` that traverse via intermediate `LambdaMap` instances ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java index 198e9feb9..36b394970 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java @@ -4,8 +4,10 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.traversable.LambdaIterable; +import com.jnape.palatable.lambda.traversable.LambdaMap; import com.jnape.palatable.lambda.traversable.Traversable; +import java.util.Map; import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -83,4 +85,17 @@ TravApp extends Traversable> AppTrav sequence(TravApp traversable, AppIterable sequence(IterableApp iterableApp, Function, ? extends AppIterable> pure) { return Sequence.sequence(iterableApp).apply(pure); } + + @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) + public static , AppMap extends Applicative, App>, MapApp extends Map> + Fn1, ? extends AppMap>, AppMap> sequence(MapApp mapApp) { + return pure -> (AppMap) Sequence., LambdaMap, AppB, Applicative, App>, LambdaMap>sequence( + LambdaMap.wrap(mapApp), x -> pure.apply(x.unwrap()).fmap(LambdaMap::wrap)) + .fmap(LambdaMap::unwrap); + } + + public static , AppMap extends Applicative, App>, MapApp extends Map> + AppMap sequence(MapApp mapApp, Function, ? extends AppMap> pure) { + return Sequence.sequence(mapApp).apply(pure); + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Difference.java b/src/main/java/com/jnape/palatable/lambda/monoid/Difference.java index b94905a37..c7be8aab3 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/Difference.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/Difference.java @@ -22,7 +22,6 @@ public Iterable identity() { return Collections::emptyIterator; } - @Override public Iterable apply(Iterable xs, Iterable ys) { return () -> { 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 07e5e843a..8a40c9cb5 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -8,20 +8,17 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten; -import static com.jnape.palatable.lambda.functions.builtin.fn2.CartesianProduct.cartesianProduct; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight.foldRight; import static java.util.Collections.emptyList; import static java.util.Collections.singleton; /** - * Wrap an {@link Iterable} in a {@link Traversable} such that {@link Traversable#traverse(Function, Function)} applies - * its computation against each element of the wrapped {@link Iterable}. Returns the result of pure if the - * wrapped {@link Iterable} is empty. + * Extension point for {@link Iterable} to adapt lambda core types like {@link Monad} and {@link Traversable}. * - * @param the Iterable element type + * @param the {@link Iterable} element type + * @see LambdaMap */ public final class LambdaIterable implements Monad, Traversable { private final Iterable as; @@ -34,7 +31,7 @@ private LambdaIterable(Iterable as) { /** * Unwrap the underlying {@link Iterable}. * - * @return the wrapped Iterable + * @return the wrapped {@link Iterable} */ public Iterable unwrap() { return as; @@ -61,10 +58,8 @@ public LambdaIterable pure(B b) { * @return the zipped LambdaIterable */ @Override - @SuppressWarnings("Convert2MethodRef") public LambdaIterable zip(Applicative, LambdaIterable> appFn) { - return wrap(map(into((f, x) -> f.apply(x)), - cartesianProduct(appFn.>>coerce().unwrap(), as))); + return Monad.super.zip(appFn).coerce(); } @Override @@ -127,7 +122,7 @@ public static LambdaIterable wrap(Iterable as) { * Construct an empty {@link LambdaIterable} by wrapping {@link java.util.Collections#emptyList()}. * * @param the Iterable element type - * @return a {@link LambdaIterable} wrapping Collections.emptyList() + * @return an empty {@link LambdaIterable} */ public static LambdaIterable empty() { return wrap(emptyList()); diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java new file mode 100644 index 000000000..20205a419 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java @@ -0,0 +1,96 @@ +package com.jnape.palatable.lambda.traversable; + +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Functor; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; +import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap; +import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; +import static java.util.Collections.emptyMap; + +/** + * Extension point for {@link Map} to adapt lambda core types like {@link Functor} and {@link Traversable}. + * + * @param the {@link Map} element type + * @see LambdaIterable + */ +public final class LambdaMap implements Functor>, Traversable> { + private final Map map; + + private LambdaMap(Map map) { + this.map = map; + } + + /** + * Unwrap the underlying {@link Map}. + * + * @return the wrapped {@link Map} + */ + public Map unwrap() { + return map; + } + + @Override + public LambdaMap fmap(Function fn) { + return wrap(toMap(HashMap::new, map(entry -> tuple(entry.getKey(), fn.apply(entry.getValue())), map.entrySet()))); + } + + @Override + @SuppressWarnings("unchecked") + public >, AppC extends Applicative, AppTrav extends Applicative> AppTrav traverse( + Function fn, Function pure) { + return foldLeft(Fn2., AppTrav>fn2(appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> { + ((LambdaMap) m).unwrap().put(k, v); + return (TravC) m; + })))).toBiFunction(), + pure.apply((TravC) LambdaMap.wrap(new HashMap<>())), + this.fmap(fn).unwrap().entrySet()); + } + + @Override + public boolean equals(Object other) { + return other instanceof LambdaMap && Objects.equals(map, ((LambdaMap) other).map); + } + + @Override + public int hashCode() { + return Objects.hash(map); + } + + @Override + public String toString() { + return "LambdaMap{map=" + map + '}'; + } + + /** + * Wrap a {@link Map} in a {@link LambdaMap}. + * + * @param map the {@link Map} + * @param the key type + * @param the value type + * @return the {@link Map} wrapped in a {@link LambdaMap} + */ + public static LambdaMap wrap(Map map) { + return new LambdaMap<>(map); + } + + /** + * Construct an empty {@link LambdaMap} by wrapping {@link Collections#emptyMap()} + * + * @param the key type + * @param the value type + * @return an empty {@link LambdaMap} + */ + public static LambdaMap empty() { + return wrap(emptyMap()); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java index 73b45f407..e51dfbaa1 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java @@ -13,6 +13,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn2.Sequence.sequence; import static java.util.Arrays.asList; +import static java.util.Collections.singletonMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static testsupport.matchers.IterableMatcher.iterates; @@ -49,6 +50,12 @@ public void iterableSpecialization() { iterates(1, 2)); } + @Test + public void mapSpecialization() { + assertEquals(right(singletonMap("foo", 1)), + sequence(singletonMap("foo", right(1)), Either::right)); + } + @Test public void compilation() { Either> a = sequence(just(right(1)), Either::right); diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java new file mode 100644 index 000000000..9cffe9efb --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java @@ -0,0 +1,28 @@ +package com.jnape.palatable.lambda.traversable; + +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.runner.RunWith; +import testsupport.traits.FunctorLaws; +import testsupport.traits.TraversableLaws; + +import java.util.HashMap; + +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static java.util.Collections.singletonMap; + +@RunWith(Traits.class) +public class LambdaMapTest { + + @TestTraits({FunctorLaws.class, TraversableLaws.class}) + public Subjects> testSubject() { + return subjects(LambdaMap.empty(), + LambdaMap.wrap(singletonMap(1, "foo")), + LambdaMap.wrap(new HashMap() {{ + put(1, "foo"); + put(2, "bar"); + put(3, "baz"); + }})); + } +} \ No newline at end of file From e65b0bc4a747bd43654a5656469a9d1b5661cc41 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 17 Jun 2018 15:19:03 -0500 Subject: [PATCH 045/348] Intersection (lazy iterable intersection), and tightening up javadocs --- CHANGELOG.md | 3 +- .../lambda/monoid/builtin/Union.java | 8 ++-- .../builtin}/Difference.java | 24 ++++++---- .../semigroup/builtin/Intersection.java | 47 +++++++++++++++++++ .../builtin}/DifferenceTest.java | 9 +--- .../semigroup/builtin/IntersectionTest.java | 43 +++++++++++++++++ 6 files changed, 113 insertions(+), 21 deletions(-) rename src/main/java/com/jnape/palatable/lambda/{monoid => semigroup/builtin}/Difference.java (62%) create mode 100644 src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java rename src/test/java/com/jnape/palatable/lambda/{monoid => semigroup/builtin}/DifferenceTest.java (88%) create mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index c590b71c9..3027e1987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `CmpEqBy`, `CmpEq`, `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` inequality checks - `MinBy`, `MaxBy`, `Min`, and `Max` semigroups - `Product2-8` interfaces, representing general product types -- `Union`, a semigroup that behaves like a lazy set union on `Iterable`s +- `Union`, a monoid that behaves like a lazy set union on `Iterable`s - `Difference`, a semigroup that behaves like a partially lazy set difference on `Iterable`s - `LambdaMap`, extension point for `j.u.Map`, similar to `LambdaIterable` - `Sequence#sequence` overloads for `j.u.Map` that traverse via intermediate `LambdaMap` instances +- `Intersection`, a semigroup that behaves like a lazy set intersection on `Iterable`s ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java index 3937d1146..d119e0a50 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java @@ -1,17 +1,17 @@ package com.jnape.palatable.lambda.monoid.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct; import com.jnape.palatable.lambda.iteration.UnioningIterable; import com.jnape.palatable.lambda.monoid.Monoid; import java.util.Collections; /** - * Given two {@link Iterable}s, return the union of all unique occurrences of elements between them. Note that this - * operation preserves order, so the unique elements of the first {@link Iterable} are iterated before the unique - * elements of the second {@link Iterable}. + * Given two {@link Iterable Iterables} xs and ys, return the {@link Concat concatenation} of + * the {@link Distinct distinct} elements of both xs and ys. * - * @param the {@link Iterable} element type) + * @param the {@link Iterable} element type */ public final class Union implements Monoid> { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Difference.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Difference.java similarity index 62% rename from src/main/java/com/jnape/palatable/lambda/monoid/Difference.java rename to src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Difference.java index c7be8aab3..b1df01f77 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/Difference.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Difference.java @@ -1,8 +1,9 @@ -package com.jnape.palatable.lambda.monoid; +package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct; +import com.jnape.palatable.lambda.semigroup.Semigroup; -import java.util.Collections; import java.util.HashSet; import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; @@ -10,18 +11,23 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; -public final class Difference implements Monoid> { +/** + * Given two {@link Iterable Iterables} xs and ys, return the {@link Distinct distinct} + * elements of xs that are not in ys. Note that this is not symmetric + * difference. + *

+ * This operation preserves order, so the resulting elements from xs are iterated in the order that + * they uniquely occur in. + * + * @param the {@link Iterable} element type + */ +public final class Difference implements Semigroup> { private static final Difference INSTANCE = new Difference(); private Difference() { } - @Override - public Iterable identity() { - return Collections::emptyIterator; - } - @Override public Iterable apply(Iterable xs, Iterable ys) { return () -> { @@ -31,7 +37,7 @@ public Iterable apply(Iterable xs, Iterable ys) { if (empty(ys)) return distinct(xs).iterator(); - //todo: pre-order dfs fold the expression tree to make stack-safe + //todo: a pre-order depth-first fold of the expression tree would make this stack-safe HashSet uniqueYs = toCollection(HashSet::new, ys); return distinct(filter(a -> !uniqueYs.contains(a), xs)).iterator(); }; diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java new file mode 100644 index 000000000..044763f83 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java @@ -0,0 +1,47 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import java.util.HashSet; +import java.util.Set; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find; + +/** + * Given two {@link Iterable Iterables} xs and ys, return the {@link Distinct distinct} + * elements of xs that are also in ys in order of their unique occurrence in xs. + * + * @param the {@link Iterable} element type + */ +public final class Intersection implements Semigroup> { + + private static final Intersection INSTANCE = new Intersection(); + + private Intersection() { + } + + @Override + public Iterable apply(Iterable xs, Iterable ys) { + Set seen = new HashSet<>(); + return distinct(filter(a -> seen.contains(a) || find(eq(a), ys).peek(seen::add).fmap(constantly(true)).orElse(false), xs)); + } + + @SuppressWarnings("unchecked") + public static Intersection intersection() { + return INSTANCE; + } + + public static Fn1, Iterable> intersection(Iterable xs) { + return Intersection.intersection().apply(xs); + } + + public static Iterable intersection(Iterable xs, Iterable ys) { + return intersection(xs).apply(ys); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/DifferenceTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/DifferenceTest.java similarity index 88% rename from src/test/java/com/jnape/palatable/lambda/monoid/DifferenceTest.java rename to src/test/java/com/jnape/palatable/lambda/semigroup/builtin/DifferenceTest.java index 66beb9cad..929a2b9f8 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/DifferenceTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/DifferenceTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.monoid; +package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -11,7 +11,7 @@ import testsupport.traits.InfiniteIterableSupport; import testsupport.traits.Laziness; -import static com.jnape.palatable.lambda.monoid.Difference.difference; +import static com.jnape.palatable.lambda.semigroup.builtin.Difference.difference; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -27,11 +27,6 @@ public Fn1, Iterable> testSubject() { return Difference.difference().flip().apply(asList(1, 2, 3)); } - @Test - public void identity() { - assertThat(difference().identity(), isEmpty()); - } - @Test public void semigroup() { assertThat(difference(emptyList(), emptyList()), isEmpty()); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java new file mode 100644 index 000000000..0ecd33c71 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java @@ -0,0 +1,43 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.EmptyIterableSupport; +import testsupport.traits.FiniteIteration; +import testsupport.traits.InfiniteIterableSupport; +import testsupport.traits.Laziness; + +import static com.jnape.palatable.lambda.semigroup.builtin.Intersection.intersection; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IterableMatcher.isEmpty; +import static testsupport.matchers.IterableMatcher.iterates; + +@RunWith(Traits.class) +public class IntersectionTest { + + @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, FiniteIteration.class}) + public Fn1, Iterable> testSubject() { + return intersection(asList(0, 1, 2, 3)); + } + + @Test + public void intersectionOfEmptyOnEitherSideIsEmpty() { + assertThat(intersection(emptyList(), singletonList(1)), isEmpty()); + assertThat(intersection(singletonList(1), emptyList()), isEmpty()); + assertThat(intersection(emptyList(), emptyList()), isEmpty()); + } + + @Test + public void intersectionIsCommonElementsAcrossIterables() { + assertThat(intersection(asList(1, 2, 3), asList(1, 2, 3)), iterates(1, 2, 3)); + assertThat(intersection(asList(1, 2, 3), asList(2, 3, 4)), iterates(2, 3)); + assertThat(intersection(singletonList(1), singletonList(2)), isEmpty()); + assertThat(intersection(asList(1, 2, 3, 3), singletonList(3)), iterates(3)); + } +} \ No newline at end of file From 75baa5e7d35e8771e7dd863d9afbcfa3067dc4ea Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 17 Jun 2018 16:04:34 -0500 Subject: [PATCH 046/348] Fn0, the function taking "no arguments" (Unit) --- CHANGELOG.md | 2 + .../jnape/palatable/lambda/functions/Fn0.java | 140 ++++++++++++++++++ .../jnape/palatable/lambda/functions/Fn1.java | 11 ++ .../jnape/palatable/lambda/functions/Fn3.java | 2 +- .../jnape/palatable/lambda/functions/Fn4.java | 2 +- .../jnape/palatable/lambda/functions/Fn5.java | 2 +- .../jnape/palatable/lambda/functions/Fn6.java | 2 +- .../jnape/palatable/lambda/functions/Fn7.java | 2 +- .../jnape/palatable/lambda/functions/Fn8.java | 2 +- .../palatable/lambda/functions/Fn0Test.java | 20 +++ .../palatable/lambda/functions/Fn1Test.java | 6 + .../java/testsupport/EqualityAwareFn0.java | 67 +++++++++ 12 files changed, 252 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/Fn0.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java create mode 100644 src/test/java/testsupport/EqualityAwareFn0.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3027e1987..f7edbd4e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `LambdaMap`, extension point for `j.u.Map`, similar to `LambdaIterable` - `Sequence#sequence` overloads for `j.u.Map` that traverse via intermediate `LambdaMap` instances - `Intersection`, a semigroup that behaves like a lazy set intersection on `Iterable`s +- `Fn0`, a function from `Unit` to some value +- `Fn1#thunk`, producing an `Fn0` ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java new file mode 100644 index 000000000..c3599b84f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -0,0 +1,140 @@ +package com.jnape.palatable.lambda.functions; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; +import java.util.function.Supplier; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; + +/** + * A function taking "no arguments", implemented as an {@link Fn1}<{@link Unit}, A>. + * + * @param the result type + * @see Fn1 + * @see Supplier + */ +@FunctionalInterface +public interface Fn0 extends Fn1, Supplier { + + /** + * Invoke this function with {@link Unit}. + * + * @param unit the only allowed input + * @return the result value + */ + @Override + A apply(Unit unit); + + /** + * Apply this {@link Fn0}, supplying {@link Unit} as the input. + * + * @return the output + */ + default A apply() { + return apply(UNIT); + } + + @Override + default Fn0 flatMap(Function>> f) { + return Fn1.super.flatMap(f)::apply; + } + + @Override + default Fn0 fmap(Function f) { + return Fn1.super.fmap(f)::apply; + } + + @Override + default Fn0 pure(B b) { + return Fn1.super.pure(b)::apply; + } + + @Override + default Fn0 zip(Applicative, Fn1> appFn) { + return Fn1.super.zip(appFn)::apply; + } + + @Override + default Fn0 zip(Fn2 appFn) { + return Fn1.super.zip(appFn)::apply; + } + + @Override + default Fn0 discardL(Applicative> appB) { + return Fn1.super.discardL(appB)::apply; + } + + @Override + default Fn0 discardR(Applicative> appB) { + return Fn1.super.discardR(appB)::apply; + } + + @Override + default Fn0 diMapR(Function fn) { + return Fn1.super.diMapR(fn)::apply; + } + + @Override + default Fn1 compose(Function before) { + return Fn1.super.compose(before)::apply; + } + + @Override + default Fn0 andThen(Function after) { + return Fn1.super.andThen(after)::apply; + } + + @Override + default A get() { + return apply(UNIT); + } + + /** + * Convenience method for converting a {@link Supplier} to an {@link Fn0}. + * + * @param supplier the supplier + * @param the output type + * @return the {@link Fn0} + */ + static Fn0 fn0(Supplier supplier) { + return __ -> supplier.get(); + } + + /** + * Static factory method for coercing a lambda to an {@link Fn0}. + * + * @param fn the lambda to coerce + * @param the output type + * @return the {@link Fn0} + */ + static Fn0 fn0(Fn0 fn) { + return fn; + } + + /** + * Static factory method for adapting a {@link Runnable} to an {@link Fn0}<{@link Unit}>. + * + * @param fn the {@link Runnable} + * @return the {@link Fn0} + */ + static Fn0 fn0(Runnable fn) { + return unit -> { + fn.run(); + return unit; + }; + } + + /** + * Static factory method for adapting a {@link Function} to an {@link Fn0}. + * + * @param fn the {@link Function} + * @param the output type + * @return the {@link Fn0} + */ + static Fn0 fn0(Function fn) { + return fn0(() -> fn.apply(UNIT)); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 608d57fd5..140206777 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -27,6 +27,17 @@ public interface Fn1 extends Monad>, Profunctor, F */ B apply(A a); + /** + * Convert this {@link Fn1} to an {@link Fn0} by supplying an argument to this function. Useful for fixing an + * argument now, but deferring application until a later time. + * + * @param a the argument + * @return an {@link Fn0} + */ + default Fn0 thunk(A a) { + return __ -> apply(a); + } + @Override default Fn1 flatMap(Function>> f) { return a -> f.apply(apply(a)).>coerce().apply(a); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java index 4662543fe..7af5bb8f8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java @@ -128,7 +128,7 @@ static Fn3 fn3(Fn2> curriedFn2) { } /** - * Static factory method for coercing a lambda to an {@link Fn3}; + * Static factory method for coercing a lambda to an {@link Fn3}. * * @param fn the lambda to coerce * @param the first input argument type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java index 496fb3aad..c3f48cff0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java @@ -160,7 +160,7 @@ static Fn4 fn4(Fn3> curriedFn3 } /** - * Static factory method for coercing a lambda to an {@link Fn4}; + * Static factory method for coercing a lambda to an {@link Fn4}. * * @param fn the lambda to coerce * @param the first input argument type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java index 887e6c964..2d6a118ef 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java @@ -195,7 +195,7 @@ static Fn5 fn5(Fn4> c } /** - * Static factory method for coercing a lambda to an {@link Fn5}; + * Static factory method for coercing a lambda to an {@link Fn5}. * * @param fn the lambda to coerce * @param the first input argument type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java index 643a2a831..cd7ca2f95 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java @@ -233,7 +233,7 @@ static Fn6 fn6(Fn5 the first input argument type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index 6bf237963..3e5d82354 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -274,7 +274,7 @@ static Fn7 fn7(Fn6 the first input argument type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java index 238c2f0a8..9d5020687 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java @@ -324,7 +324,7 @@ static Fn8 fn8( } /** - * Static factory method for coercing a lambda to an {@link Fn8}; + * Static factory method for coercing a lambda to an {@link Fn8}. * * @param fn the lambda to coerce * @param the first input argument type diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java new file mode 100644 index 000000000..d57027c70 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.functions; + +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.runner.RunWith; +import testsupport.EqualityAwareFn0; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; + +@RunWith(Traits.class) +public class Fn0Test { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public Fn0 testSubject() { + return new EqualityAwareFn0<>(constantly(1)::apply); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index fa3881d40..f1e244a7c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -35,4 +35,10 @@ public void fn1() { Function parseInt = Integer::parseInt; assertEquals((Integer) 1, Fn1.fn1(parseInt).apply("1")); } + + @Test + public void thunk() { + Fn1 toString = Object::toString; + assertEquals("1", toString.thunk(1).apply()); + } } diff --git a/src/test/java/testsupport/EqualityAwareFn0.java b/src/test/java/testsupport/EqualityAwareFn0.java new file mode 100644 index 000000000..188c5b49b --- /dev/null +++ b/src/test/java/testsupport/EqualityAwareFn0.java @@ -0,0 +1,67 @@ +package testsupport; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static java.util.Objects.hash; + +public final class EqualityAwareFn0 implements Fn0 { + private final Fn0 fn; + + public EqualityAwareFn0(Fn0 fn) { + this.fn = fn; + } + + @Override + public A apply(Unit unit) { + return fn.apply(unit); + } + + @Override + public EqualityAwareFn0 flatMap(Function>> f) { + return new EqualityAwareFn0<>(fn.flatMap(f)); + } + + @Override + public EqualityAwareFn0 fmap(Function f) { + return new EqualityAwareFn0<>(fn.fmap(f)); + } + + @Override + public EqualityAwareFn0 zip(Applicative, Fn1> appFn) { + return new EqualityAwareFn0<>(fn.zip(appFn)); + } + + @Override + public EqualityAwareFn0 pure(B b) { + return new EqualityAwareFn0<>(fn.pure(b)); + } + + + @Override + public EqualityAwareFn0 discardL(Applicative> appB) { + return new EqualityAwareFn0<>(fn.discardL(appB)); + } + + @Override + public EqualityAwareFn0 discardR(Applicative> appB) { + return new EqualityAwareFn0<>(fn.discardR(appB)); + } + + @Override + @SuppressWarnings("unchecked") + public boolean equals(Object other) { + return other instanceof Fn0 && ((Fn0) other).apply(UNIT).equals(apply(UNIT)); + } + + @Override + public int hashCode() { + return hash(fn); + } +} From c4907a02456426894713e3cb2b40678f611a3215 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 4 Jul 2018 09:03:55 -0400 Subject: [PATCH 047/348] Absent, a semigroup over Maybe that is absent-biased --- CHANGELOG.md | 1 + .../lambda/monoid/builtin/Absent.java | 53 +++++++++++++++++++ .../lambda/monoid/builtin/Present.java | 1 + .../lambda/monoid/builtin/AbsentTest.java | 23 ++++++++ 4 files changed, 78 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monoid/builtin/Absent.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monoid/builtin/AbsentTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f7edbd4e1..3ddd74cec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Intersection`, a semigroup that behaves like a lazy set intersection on `Iterable`s - `Fn0`, a function from `Unit` to some value - `Fn1#thunk`, producing an `Fn0` +- `Absent`, a monoid over `Maybe` that is absence biased ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Absent.java new file mode 100644 index 000000000..db38aad3e --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Absent.java @@ -0,0 +1,53 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn3.LiftA2; +import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +/** + * A {@link Semigroup} instance formed by {@link Maybe}<A> and a semigroup over A. The + * application to two {@link Maybe} values is absence-biased, such that for a given {@link Maybe} x + * and y: + *

+ * + * @param the Maybe value parameter type + * @see Semigroup + * @see Present + * @see Maybe + */ +public final class Absent implements SemigroupFactory, Maybe> { + + private static final Absent INSTANCE = new Absent<>(); + + private Absent() { + } + + @Override + public Semigroup> apply(Semigroup aSemigroup) { + return LiftA2., Maybe, Maybe>liftA2(aSemigroup.toBiFunction())::apply; + } + + @SuppressWarnings("unchecked") + public static Absent absent() { + return INSTANCE; + } + + public static Semigroup> absent(Semigroup semigroup) { + return Absent.absent().apply(semigroup); + } + + public static Fn1, Maybe> absent(Semigroup aSemigroup, Maybe x) { + return absent(aSemigroup).apply(x); + } + + public static Maybe absent(Semigroup semigroup, Maybe x, Maybe y) { + return absent(semigroup, x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java index aa1433c77..af2a51ee5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java @@ -23,6 +23,7 @@ * * @param the Maybe value parameter type * @see Monoid + * @see Absent * @see Maybe */ public final class Present implements MonoidFactory, Maybe> { diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AbsentTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AbsentTest.java new file mode 100644 index 000000000..6a0196daa --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AbsentTest.java @@ -0,0 +1,23 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.semigroup.Semigroup; +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.monoid.builtin.Absent.absent; +import static org.junit.Assert.assertEquals; + +public class AbsentTest { + + @Test + public void monoid() { + Absent absent = absent(); + Semigroup addition = (x, y) -> x + y; + + assertEquals(just(3), absent.apply(addition, just(1), just(2))); + assertEquals(nothing(), absent.apply(addition, nothing(), just(1))); + assertEquals(nothing(), absent.apply(addition, just(1), nothing())); + assertEquals(nothing(), absent.apply(addition, nothing(), nothing())); + } +} \ No newline at end of file From e31e3aa5fca4aad8014ca31607cbf77122dd1131 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 7 Jul 2018 18:22:03 -0500 Subject: [PATCH 048/348] Removing unnecessary throws declarations in tests --- .../jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java | 2 +- .../java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java | 2 +- .../com/jnape/palatable/lambda/monoid/builtin/MergeTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java index de58ff042..840416088 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java @@ -22,7 +22,7 @@ public class CoProduct4Test { private CoProduct4 d; @Before - public void setUp() throws Exception { + public void setUp() { a = new CoProduct4>() { @Override public R match(Function aFn, Function bFn, diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index 36f9a44cc..a5e86f825 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -29,7 +29,7 @@ public class Tuple2Test { private Tuple2 tuple2; @Before - public void setUp() throws Exception { + public void setUp() { tuple2 = new Tuple2<>(1, new SingletonHList<>(2)); } diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeTest.java index 2a7fd462d..d64e26542 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeTest.java @@ -19,7 +19,7 @@ public class MergeTest { private Monoid> merge; @Before - public void setUp() throws Exception { + public void setUp() { merge = merge(JOIN, ADD); } From ef3edfd2fedcb701a7e3ddd18730bfa366b78faa Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 7 Jul 2018 18:33:36 -0500 Subject: [PATCH 049/348] LiftA2 receives more parameters to aid inference --- CHANGELOG.md | 1 + .../lambda/functions/builtin/fn3/LiftA2.java | 48 ++++++++++--------- .../functions/builtin/fn3/LiftA2Test.java | 36 +++++++++++--- .../lambda/traversable/TraversableTest.java | 2 +- 4 files changed, 58 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ddd74cec..47bf7cfc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Into3-8` now accept a product of the same cardinality, instead of requiring a tuple - `CoProduct2-8#project` now return generalized products - `Choice2-8#project` return tuples +- `liftA2` receives more parameters to aid inference ## [3.0.3] - 2018-05-27 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java index c3dd1742b..51381ef58 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java @@ -7,20 +7,23 @@ import java.util.function.BiFunction; -import static com.jnape.palatable.lambda.functions.Fn2.fn2; - /** * Lift into and apply a {@link BiFunction} to two {@link Applicative} values, returning the result inside the same - * {@link Applicative} context. Equivalent ot appB.zip(appA.fmap(fn)). + * {@link Applicative} context. Functionally equivalent to appB.zip(appA.fmap(fn)). * - * @param the function's first argument type - * @param the function's second argument type - * @param the function's return type - * @param the applicative unification type + * @param the function's first argument type + * @param the function's second argument typ + * @param the function's return type + * @param the applicative unification type + * @param the inferred first applicative argument type + * @param the inferred second applicative argument type + * @param the inferred applicative return type * @see Applicative#zip(Applicative) */ -public final class LiftA2 implements Fn3, - Applicative, Applicative, Applicative> { +public final class LiftA2, + AppB extends Applicative, + AppC extends Applicative> implements Fn3, AppA, AppB, AppC> { private static final LiftA2 INSTANCE = new LiftA2(); @@ -28,29 +31,30 @@ private LiftA2() { } @Override - public Applicative apply(BiFunction fn, - Applicative appA, - Applicative appB) { - return appB.zip(appA.fmap(fn2(fn))); + public AppC apply(BiFunction fn, AppA appA, AppB appB) { + return appB.zip(appA.fmap(Fn2.fn2(fn))).coerce(); } @SuppressWarnings("unchecked") - public static LiftA2 liftA2() { + public static , AppB extends Applicative, AppC extends Applicative> LiftA2 liftA2() { return INSTANCE; } - public static Fn2, Applicative, Applicative> liftA2( + public static , AppB extends Applicative, AppC extends Applicative> Fn2 liftA2( BiFunction fn) { - return LiftA2.liftA2().apply(fn); + return LiftA2.liftA2().apply(fn); } - public static Fn1, Applicative> liftA2( - BiFunction fn, Applicative appA) { - return LiftA2.liftA2(fn).apply(appA); + public static , AppB extends Applicative, AppC extends Applicative> Fn1 liftA2( + BiFunction fn, + AppA appA) { + return LiftA2.liftA2(fn).apply(appA); } - public static Applicative liftA2( - BiFunction fn, Applicative appA, Applicative appB) { - return LiftA2.liftA2(fn, appA).apply(appB); + public static , AppB extends Applicative, AppC extends Applicative> AppC liftA2( + BiFunction fn, + AppA appA, + AppB appB) { + return LiftA2.liftA2(fn, appA).apply(appB); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java index 93556ebe9..1e575879d 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java @@ -1,22 +1,46 @@ package com.jnape.palatable.lambda.functions.builtin.fn3; -import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; import org.junit.Test; import java.util.function.BiFunction; +import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; -import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn3.LiftA2.liftA2; import static org.junit.Assert.assertEquals; public class LiftA2Test { @Test - public void liftsAndAppliesDyadicFunctionToTwoApplicatives() { + public void inference() { BiFunction add = (x, y) -> x + y; - assertEquals(right(3), liftA2(add, right(1), right(2)).coerce()); - assertEquals(tuple(1, 5), liftA2(add, tuple(1, 2), tuple(2, 3)).coerce()); - assertEquals(new Identity<>(3), liftA2(add, new Identity<>(1), new Identity<>(2))); + + Maybe a = liftA2(add, just(1), just(2)); + assertEquals(just(3), a); + + Maybe b = liftA2(add, just(1), nothing()); + assertEquals(nothing(), b); + + Maybe c = liftA2(add, nothing(), just(2)); + assertEquals(nothing(), c); + + Maybe d = liftA2(add, nothing(), nothing()); + assertEquals(nothing(), d); + + Either e = liftA2(add, Either.right(1), right(2)); + assertEquals(right(3), e); + + Either f = liftA2(add, left("error"), right(2)); + assertEquals(left("error"), f); + + Either g = liftA2(add, right(1), left("error")); + assertEquals(left("error"), g); + + Either h = liftA2(add, left("error"), left("another error")); + assertEquals(left("error"), h); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/TraversableTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/TraversableTest.java index f27c2b214..1bd8e5fa5 100644 --- a/src/test/java/com/jnape/palatable/lambda/traversable/TraversableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/traversable/TraversableTest.java @@ -15,7 +15,7 @@ public class TraversableTest { @Test - public void compilation() { + public void inference() { Either> a = just(Either.right(1)).traverse(id(), Either::right); assertEquals(right(just(1)), a); From ddae9517a3f8b8008a21a7aa4c89131f07a70c07 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 7 Jul 2018 19:29:38 -0500 Subject: [PATCH 050/348] RateLimit, for rate-limiting elements iterated from an Iterable --- CHANGELOG.md | 1 + .../functions/builtin/fn4/RateLimit.java | 85 +++++++++++++++++++ .../IterationInterruptedException.java | 17 ++++ .../iteration/RateLimitingIterable.java | 31 +++++++ .../iteration/RateLimitingIterator.java | 75 ++++++++++++++++ .../functions/builtin/fn4/RateLimitTest.java | 77 +++++++++++++++++ .../matchers/RateLimitedIterationMatcher.java | 68 +++++++++++++++ .../time/InstantRecordingClock.java | 42 +++++++++ 8 files changed, 396 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java create mode 100644 src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java create mode 100644 src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java create mode 100644 src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java create mode 100644 src/test/java/testsupport/matchers/RateLimitedIterationMatcher.java create mode 100644 src/test/java/testsupport/time/InstantRecordingClock.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 47bf7cfc2..572ba93c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Fn0`, a function from `Unit` to some value - `Fn1#thunk`, producing an `Fn0` - `Absent`, a monoid over `Maybe` that is absence biased +- `RateLimit`, a function that iterates elements from an `Iterable` according to some rate limit ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java new file mode 100644 index 000000000..0b0ff5104 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java @@ -0,0 +1,85 @@ +package com.jnape.palatable.lambda.functions.builtin.fn4; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.Fn4; +import com.jnape.palatable.lambda.iteration.IterationInterruptedException; +import com.jnape.palatable.lambda.iteration.RateLimitingIterable; + +import java.time.Duration; +import java.time.Instant; +import java.util.function.Supplier; + +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static java.util.Collections.singleton; + +/** + * Given a {@link Supplier} of {@link Instant Instants} (presumably backed by a clock), a limit, a {@link + * Duration}, and an {@link Iterable} as, return an {@link Iterable} that iterates as + * according to the threshold specified by the limit per duration, using the {@link Supplier} to advance time. + *

+ * As an example, the following will print at most 10 elements per second: + *


+ * rateLimit(Clock.systemUTC()::instant, 10L, Duration.ofSeconds(1), iterate(x -> x + 1, 1)).forEach(System.out::println);
+ * 
+ * Currying allows different rate limits to be combined naturally: + *

+ * Iterable elements = iterate(x -> x + 1, 1);
+ *
+ * Supplier instantSupplier = Clock.systemUTC()::instant;
+ * Fn1, Iterable> tenPerSecond = rateLimit(instantSupplier, 10L, Duration.ofSeconds(1));
+ * Fn1, Iterable> oneHundredEveryTwoMinutes = rateLimit(instantSupplier, 100L, Duration.ofMinutes(2));
+ *
+ * tenPerSecond.fmap(oneHundredEveryTwoMinutes).apply(elements).forEach(System.out::println);
+ * 
+ * In the preceding example, the elements will be printed at most 10 elements per second and 100 elements per 120 + * seconds. + *

+ * If the host {@link Thread} is {@link Thread#interrupt() interrupted} while the returned {@link Iterable} is waiting + * for the next available time slice, an {@link IterationInterruptedException} will immediately be thrown. + *

+ * Note that the returned {@link Iterable} will never iterate faster than the specified rate limit, but the earliest + * the next element is available will be dependent on the precision of the underlying instant supplier as well as any + * overhead involved in producing the element from the original {@link Iterable}. + * + * @param the {@link Iterable} element type + */ +public final class RateLimit implements Fn4, Long, Duration, Iterable, Iterable> { + + private static final RateLimit INSTANCE = new RateLimit(); + + private RateLimit() { + } + + @Override + public Iterable apply(Supplier instantSupplier, Long limit, Duration duration, Iterable as) { + if (limit < 1) + throw new IllegalArgumentException("Limit must be greater than 0: " + limit); + + return new RateLimitingIterable<>(as, singleton(tuple(limit, duration, instantSupplier))); + } + + @SuppressWarnings("unchecked") + public static RateLimit rateLimit() { + return INSTANCE; + } + + public static Fn3, Iterable> rateLimit(Supplier instantSupplier) { + return RateLimit.rateLimit().apply(instantSupplier); + } + + public static Fn2, Iterable> rateLimit(Supplier instantSupplier, Long limit) { + return RateLimit.rateLimit(instantSupplier).apply(limit); + } + + public static Fn1, Iterable> rateLimit(Supplier instantSupplier, Long limit, + Duration duration) { + return RateLimit.rateLimit(instantSupplier, limit).apply(duration); + } + + public static Iterable rateLimit(Supplier instantSupplier, Long limit, Duration duration, + Iterable as) { + return RateLimit.rateLimit(instantSupplier, limit, duration).apply(as); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java b/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java new file mode 100644 index 000000000..69b26f335 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java @@ -0,0 +1,17 @@ +package com.jnape.palatable.lambda.iteration; + +import com.jnape.palatable.lambda.functions.builtin.fn4.RateLimit; + +import java.util.Iterator; + +/** + * An exception thrown when a thread is interrupted while an {@link Iterator} was blocked. + * + * @see RateLimit + */ +public final class IterationInterruptedException extends RuntimeException { + + public IterationInterruptedException(InterruptedException cause) { + super(cause); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java new file mode 100644 index 000000000..27427b2cb --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java @@ -0,0 +1,31 @@ +package com.jnape.palatable.lambda.iteration; + +import com.jnape.palatable.lambda.adt.hlist.Tuple3; + +import java.time.Duration; +import java.time.Instant; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.function.Supplier; + +public final class RateLimitingIterable implements Iterable { + private final Iterable as; + private final Set>> rateLimits; + + public RateLimitingIterable(Iterable as, Set>> rateLimits) { + Set>> combinedRateLimits = new HashSet<>(rateLimits); + if (as instanceof RateLimitingIterable) { + RateLimitingIterable inner = (RateLimitingIterable) as; + combinedRateLimits.addAll(inner.rateLimits); + as = inner.as; + } + this.rateLimits = combinedRateLimits; + this.as = as; + } + + @Override + public Iterator iterator() { + return new RateLimitingIterator<>(as.iterator(), rateLimits); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java new file mode 100644 index 000000000..de2e7b94c --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java @@ -0,0 +1,75 @@ +package com.jnape.palatable.lambda.iteration; + +import com.jnape.palatable.lambda.adt.hlist.Tuple3; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.function.Supplier; + +import static com.jnape.palatable.lambda.adt.Try.trying; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter; +import static com.jnape.palatable.lambda.functions.builtin.fn2.GT.gt; +import static com.jnape.palatable.lambda.functions.builtin.fn2.GTE.gte; +import static com.jnape.palatable.lambda.functions.builtin.fn2.LTE.lte; +import static com.jnape.palatable.lambda.semigroup.builtin.Max.max; +import static java.lang.Thread.sleep; +import static java.util.Collections.emptyList; + +public final class RateLimitingIterator implements Iterator { + private final Iterator asIterator; + private final Set>> rateLimits; + private final Map>, List> timeSlicesByRateLimit; + + public RateLimitingIterator(Iterator asIterator, Set>> rateLimits) { + this.asIterator = asIterator; + this.rateLimits = rateLimits; + timeSlicesByRateLimit = new HashMap<>(); + } + + @Override + public boolean hasNext() { + return asIterator.hasNext(); + } + + @Override + public A next() { + if (!hasNext()) + throw new NoSuchElementException(); + awaitNextTimeSlice(); + return asIterator.next(); + } + + private void awaitNextTimeSlice() { + rateLimits.forEach(rateLimit -> { + awaitNextTimeSliceForRateLimit(rateLimit); + List timeSlicesForRateLimit = timeSlicesByRateLimit.getOrDefault(rateLimit, new ArrayList<>()); + timeSlicesForRateLimit.add(rateLimit._3().get()); + timeSlicesByRateLimit.put(rateLimit, timeSlicesForRateLimit); + }); + } + + private void awaitNextTimeSliceForRateLimit(Tuple3> rateLimit) { + while (rateLimitExhaustedInTimeSlice(rateLimit)) { + trying(() -> sleep(0)).biMapL(IterationInterruptedException::new).orThrow(); + } + } + + private boolean rateLimitExhaustedInTimeSlice(Tuple3> rateLimit) { + List timeSlicesForRateLimit = timeSlicesByRateLimit.getOrDefault(rateLimit, emptyList()); + return rateLimit.into((limit, duration, instantSupplier) -> { + Instant timeSliceEnd = instantSupplier.get(); + Instant previousTimeSliceEnd = timeSliceEnd.minus(duration); + timeSlicesForRateLimit.removeIf(gt(previousTimeSliceEnd)); + return max(0L, limit - size(filter(mark -> gte(mark, previousTimeSliceEnd) && lte(mark, timeSliceEnd), timeSlicesForRateLimit))) == 0; + }); + } + +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java new file mode 100644 index 000000000..0459a8be1 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java @@ -0,0 +1,77 @@ +package com.jnape.palatable.lambda.functions.builtin.fn4; + +import com.jnape.palatable.lambda.adt.Try; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.iteration.IterationInterruptedException; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.time.InstantRecordingClock; +import testsupport.traits.Deforesting; +import testsupport.traits.EmptyIterableSupport; +import testsupport.traits.InfiniteIterableSupport; +import testsupport.traits.Laziness; + +import java.time.Duration; +import java.util.concurrent.CountDownLatch; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; +import static com.jnape.palatable.lambda.functions.builtin.fn4.RateLimit.rateLimit; +import static java.time.Clock.systemUTC; +import static java.time.Duration.ZERO; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IterableMatcher.iterates; +import static testsupport.matchers.RateLimitedIterationMatcher.iteratesAccordingToRateLimit; + +@RunWith(Traits.class) +public class RateLimitTest { + + private InstantRecordingClock clock; + + @Before + public void setUp() throws Exception { + clock = new InstantRecordingClock(systemUTC()); + } + + @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, Deforesting.class}) + public Fn1, Iterable> testSubject() { + return rateLimit(systemUTC()::instant, 1L, ZERO); + } + + @Test(expected = IllegalArgumentException.class) + public void lessThanOneLimitIsInvalid() { + rateLimit(clock::instant, 0L, ZERO, emptyList()); + } + + @Test + public void zeroDurationJustIteratesElements() { + assertThat(rateLimit(clock::instant, 1L, ZERO, asList(1, 2, 3)), iterates(1, 2, 3)); + } + + @Test + public void limitPerDurationIsHonoredAccordingToClock() { + Duration duration = Duration.ofMillis(10); + long limit = 2L; + assertThat(rateLimit(clock::instant, limit, duration, asList(1, 2, 3, 4)), + iteratesAccordingToRateLimit(limit, duration, asList(1, 2, 3, 4), clock)); + } + + @Test(timeout = 100, expected = IterationInterruptedException.class) + public void rateLimitingDelayIsInterruptible() throws InterruptedException { + Thread testThread = Thread.currentThread(); + CountDownLatch latch = new CountDownLatch(1); + new Thread(() -> { + Try.trying(latch::await).biMapL(AssertionError::new) + .orThrow(); + testThread.interrupt(); + }) {{ + start(); + }}; + + rateLimit(clock::instant, 1L, Duration.ofSeconds(1), repeat(1)).forEach(xs -> latch.countDown()); + } +} \ No newline at end of file diff --git a/src/test/java/testsupport/matchers/RateLimitedIterationMatcher.java b/src/test/java/testsupport/matchers/RateLimitedIterationMatcher.java new file mode 100644 index 000000000..c0f2d56ab --- /dev/null +++ b/src/test/java/testsupport/matchers/RateLimitedIterationMatcher.java @@ -0,0 +1,68 @@ +package testsupport.matchers; + +import com.jnape.palatable.lambda.functions.builtin.fn2.Eq; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; +import testsupport.time.InstantRecordingClock; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Iterator; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.All.all; +import static com.jnape.palatable.lambda.functions.builtin.fn2.InGroupsOf.inGroupsOf; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Slide.slide; +import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Zip.zip; +import static java.time.Duration.between; + +public final class RateLimitedIterationMatcher extends TypeSafeMatcher> { + private final Iterable elements; + private final Duration delay; + private final InstantRecordingClock clock; + private final Long limit; + + public RateLimitedIterationMatcher(Long limit, Duration delay, Iterable elements, InstantRecordingClock clock) { + this.elements = elements; + this.delay = delay; + this.clock = clock; + this.limit = limit; + } + + @Override + protected boolean matchesSafely(Iterable xs) { + xs.forEach(__ -> clock.saveLastInstant()); + + Boolean enoughDelay = all(d -> d.toNanos() > delay.toNanos(), map(boundaries -> { + Iterator it = boundaries.iterator(); + Instant first = it.next(); + Instant second = it.next(); + return between(first, second); + }, slide(2, map(instants -> instants.iterator().next(), inGroupsOf(limit.intValue(), clock.instants()))))); + + Boolean sameElements = all(Eq.eq().uncurry(), zip(elements, xs)); + + return enoughDelay && sameElements; + } + + @Override + public void describeTo(Description description) { + description.appendText("Iterated elements " + toCollection(ArrayList::new, elements) + " with at least " + delay.toMillis() + "ms between groups of " + limit); + } + + @Override + protected void describeMismatchSafely(Iterable item, Description mismatchDescription) { + mismatchDescription.appendText("Iterated elements " + + toCollection(ArrayList::new, item) + + " with the following delays between groups: " + + toCollection(ArrayList::new, map(instants -> instants.iterator().next(), inGroupsOf(limit.intValue(), clock.instants())))); + } + + public static RateLimitedIterationMatcher iteratesAccordingToRateLimit(Long limit, Duration duration, + Iterable elements, + InstantRecordingClock clock) { + return new RateLimitedIterationMatcher<>(limit, duration, elements, clock); + } +} diff --git a/src/test/java/testsupport/time/InstantRecordingClock.java b/src/test/java/testsupport/time/InstantRecordingClock.java new file mode 100644 index 000000000..421971861 --- /dev/null +++ b/src/test/java/testsupport/time/InstantRecordingClock.java @@ -0,0 +1,42 @@ +package testsupport.time; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.List; + +public final class InstantRecordingClock extends Clock { + private final Clock clock; + private final List instants; + private Instant lastInstant; + + public InstantRecordingClock(Clock clock) { + this.clock = clock; + instants = new ArrayList<>(); + } + + @Override + public ZoneId getZone() { + return clock.getZone(); + } + + @Override + public Clock withZone(ZoneId zone) { + return new InstantRecordingClock(clock.withZone(zone)); + } + + @Override + public Instant instant() { + return lastInstant = clock.instant(); + } + + public Instant saveLastInstant() { + instants.add(lastInstant); + return lastInstant; + } + + public List instants() { + return instants; + } +} From 962a3c4ff2e9c445dbeb5a9c264b83af8eb57c4d Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 8 Jul 2018 15:34:07 -0500 Subject: [PATCH 051/348] Try#withResources --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/adt/Try.java | 81 +++++++++++++++++++ .../jnape/palatable/lambda/adt/TryTest.java | 59 ++++++++++++++ 3 files changed, 141 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 572ba93c2..3cf4c1cfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Fn1#thunk`, producing an `Fn0` - `Absent`, a monoid over `Maybe` that is absence biased - `RateLimit`, a function that iterates elements from an `Iterable` according to some rate limit +- `Try#withResources`, `Try`'s expression analog to Java 7's try-with-resources statement ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index 0a2169f09..74dded5cb 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1; import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable; import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functor.Applicative; @@ -15,6 +16,7 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek2.peek2; /** @@ -246,6 +248,85 @@ public static Try trying(CheckedRunnable runna }); } + /** + * Given a {@link CheckedSupplier}<{@link AutoCloseable}> aSupplier and a + * {@link Function} fn, apply fn to the result of aSupplier, ensuring + * that the result has its {@link AutoCloseable#close() close} method invoked, regardless of the outcome. + *

+ * If the resource creation process throws, the function body throws, or the + * {@link AutoCloseable#close() close method} throws, the result is a failure. If both the function body and the + * {@link AutoCloseable#close() close method} throw, the result is a failure over the function body + * {@link Throwable} with the {@link AutoCloseable#close() close method} {@link Throwable} added as a + * {@link Throwable#addSuppressed(Throwable) suppressed} {@link Throwable}. If only the + * {@link AutoCloseable#close() close method} throws, the result is a failure over that {@link Throwable}. + *

+ * Note that withResources calls can be nested, in which case all of the above specified exception + * handling applies, where closing the previously created resource is considered part of the body of the next + * withResources calls, and {@link Throwable Throwables} are considered suppressed in the same manner. + * Additionally, {@link AutoCloseable#close() close methods} are invoked in the inverse order of resource creation. + *

+ * This is {@link Try}'s equivalent of + * + * try-with-resources, introduced in Java 7. + * + * @param aSupplier the resource supplier + * @param fn the function body + * @param the resource type + * @param the function return type + * @return a {@link Try} representing the result of the function's application to the resource + */ + public static Try withResources( + CheckedSupplier aSupplier, + CheckedFn1> fn) { + return trying(() -> { + try (A resource = aSupplier.get()) { + return fn.apply(resource).biMap(upcast(), upcast()); + } + }).flatMap(id()); + } + + /** + * Convenience overload of {@link Try#withResources(CheckedSupplier, CheckedFn1) withResources} that cascades + * dependent resource creation via nested calls. + * + * @param aSupplier the first resource supplier + * @param bFn the dependent resource function + * @param fn the function body + * @param the first resource type + * @param the second resource type + * @param the function return type + * @return a {@link Try} representing the result of the function's application to the dependent resource + */ + public static Try withResources( + CheckedSupplier aSupplier, + CheckedFn1 bFn, + CheckedFn1> fn) { + return withResources(aSupplier, a -> withResources(() -> bFn.apply(a), fn::apply)); + } + + /** + * Convenience overload of {@link Try#withResources(CheckedSupplier, CheckedFn1, CheckedFn1) withResources} that + * cascades + * two dependent resource creations via nested calls. + * + * @param aSupplier the first resource supplier + * @param bFn the second resource function + * @param cFn the final resource function + * @param fn the function body + * @param the first resource type + * @param the second resource type + * @param the final resource type + * @param the function return type + * @return a {@link Try} representing the result of the function's application to the final dependent resource + */ + public static Try withResources( + CheckedSupplier aSupplier, + CheckedFn1 bFn, + CheckedFn1 cFn, + CheckedFn1> fn) { + return withResources(aSupplier, bFn, b -> withResources(() -> cFn.apply(b), fn::apply)); + } + private static final class Failure extends Try { private final T t; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index 362671cf6..f0c7cb043 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -12,6 +12,10 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import static com.jnape.palatable.lambda.adt.Either.left; @@ -22,11 +26,15 @@ import static com.jnape.palatable.lambda.adt.Try.success; import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static testsupport.matchers.LeftMatcher.isLeftThat; @RunWith(Traits.class) @@ -150,4 +158,55 @@ public void tryingCatchesAnyThrowableThrownDuringEvaluation() { assertEquals(success("foo"), trying(() -> "foo")); } + + @Test + public void withResourcesCleansUpAutoCloseableInSuccessCase() { + AtomicBoolean closed = new AtomicBoolean(false); + assertEquals(Try.success(1), Try.withResources(() -> () -> closed.set(true), resource -> success(1))); + assertTrue(closed.get()); + } + + @Test + public void withResourcesCleansUpAutoCloseableInFailureCase() { + AtomicBoolean closed = new AtomicBoolean(false); + RuntimeException exception = new RuntimeException(); + assertEquals(Try.failure(exception), Try.withResources(() -> () -> closed.set(true), + resource -> { throw exception; })); + assertTrue(closed.get()); + } + + @Test + public void withResourcesExposesResourceCreationFailure() { + IOException ioException = new IOException(); + assertEquals(Try.failure(ioException), Try.withResources(() -> { throw ioException; }, resource -> success(1))); + } + + @Test + public void withResourcesExposesResourceCloseFailure() { + IOException ioException = new IOException(); + assertEquals(Try.failure(ioException), Try.withResources(() -> () -> { throw ioException; }, + resource -> success(1))); + } + + @Test + public void withResourcesPreservesSuppressedExceptionThrownDuringClose() { + RuntimeException rootException = new RuntimeException(); + IOException nestedIOException = new IOException(); + Try failure = Try.withResources(() -> () -> { throw nestedIOException; }, + resource -> { throw rootException; }); + Exception thrown = failure.recover(id()); + + assertEquals(thrown, rootException); + assertArrayEquals(new Throwable[]{nestedIOException}, thrown.getSuppressed()); + } + + @Test + public void cascadingWithResourcesClosesInInverseOrder() { + List closeMessages = new ArrayList<>(); + assertEquals(success(1), Try.withResources(() -> (AutoCloseable) () -> closeMessages.add("close a"), + a -> () -> closeMessages.add("close b"), + b -> () -> closeMessages.add("close c"), + c -> success(1))); + assertEquals(asList("close c", "close b", "close a"), closeMessages); + } } \ No newline at end of file From 9b47b285c9c348f60ad7120cc038ffebe0978a8b Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 9 Jul 2018 22:44:15 -0500 Subject: [PATCH 052/348] Occurrences, for counting the occurrences of elements in an Iterable --- CHANGELOG.md | 1 + .../functions/builtin/fn1/Occurrences.java | 38 +++++++++++++++++++ .../builtin/fn1/OccurrencesTest.java | 28 ++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cf4c1cfd..2e0357890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Absent`, a monoid over `Maybe` that is absence biased - `RateLimit`, a function that iterates elements from an `Iterable` according to some rate limit - `Try#withResources`, `Try`'s expression analog to Java 7's try-with-resources statement +- `Occurrences`, for counting the occurrences of the members of an `Iterable` ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java new file mode 100644 index 000000000..8a9062942 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java @@ -0,0 +1,38 @@ +package com.jnape.palatable.lambda.functions.builtin.fn1; + +import com.jnape.palatable.lambda.functions.Fn1; + +import java.util.HashMap; +import java.util.Map; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; + +/** + * Given an {@link Iterable}<A>, return a {@link Map}<A, Long> representing each + * unique element in the {@link Iterable} paired with its number of occurrences. + * + * @param the {@link Iterable} element type + */ +public final class Occurrences implements Fn1, Map> { + private static final Occurrences INSTANCE = new Occurrences(); + + private Occurrences() { + } + + @Override + public Map apply(Iterable as) { + return foldLeft((occurrences, a) -> { + occurrences.put(a, occurrences.getOrDefault(a, 0L) + 1); + return occurrences; + }, new HashMap<>(), as); + } + + @SuppressWarnings("unchecked") + public static Occurrences occurrences() { + return INSTANCE; + } + + public static Map occurrences(Iterable as) { + return Occurrences.occurrences().apply(as); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java new file mode 100644 index 000000000..bb11d5782 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java @@ -0,0 +1,28 @@ +package com.jnape.palatable.lambda.functions.builtin.fn1; + +import org.junit.Test; + +import java.util.HashMap; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Occurrences.occurrences; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.junit.Assert.assertEquals; + +public class OccurrencesTest { + + @Test + public void occurrencesOfIndividualElements() { + assertEquals(new HashMap() {{ + put("foo", 2L); + put("bar", 2L); + put("baz", 1L); + }}, occurrences(asList("foo", "bar", "foo", "baz", "bar"))); + } + + @Test + public void emptyIterableHasNoOccurrences() { + assertEquals(emptyMap(), occurrences(emptyList())); + } +} From d01c6da10f2abff2d4935560324490a709beecb5 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 11 Jul 2018 17:53:21 -0500 Subject: [PATCH 053/348] Either#trying can now throw any Throwable --- .../jnape/palatable/lambda/adt/Either.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) 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 0fbcf2dd5..be6ed52ac 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -283,14 +283,14 @@ public static Either fromMaybe(Maybe maybe, Supplier leftFn) * * @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 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 */ - public static Either trying(CheckedSupplier supplier, - Function leftFn) { - return Try.trying(supplier::get).toEither(leftFn); + public static Either trying(CheckedSupplier supplier, + Function leftFn) { + return Try.trying(supplier::get).toEither(leftFn); } /** @@ -298,11 +298,11 @@ public static Either trying(CheckedSupplier the left parameter type (the most contravariant exception that supplier might throw) + * @param 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) { + public static Either trying(CheckedSupplier supplier) { return trying(supplier, id()); } @@ -312,12 +312,12 @@ public static Either trying(CheckedSupplier * * @param runnable the runnable * @param leftFn a function mapping E to L - * @param the most contravariant exception that the runnable might throw + * @param the most contravariant exception that the runnable might throw * @param the left parameter type * @return {@link Unit} as a right value, or leftFn's mapping result as a left value */ - public static Either trying(CheckedRunnable runnable, - Function leftFn) { + public static Either trying(CheckedRunnable runnable, + Function leftFn) { return Try.trying(runnable).toEither(leftFn); } @@ -326,10 +326,10 @@ public static Either trying(CheckedRunnable * exception, wrap it in a left value and return it. * * @param runnable the runnable - * @param the left parameter type (the most contravariant exception that runnable might throw) + * @param the left parameter type (the most contravariant exception that runnable might throw) * @return {@link Unit} as a right value, or a left value of the thrown exception */ - public static Either trying(CheckedRunnable runnable) { + public static Either trying(CheckedRunnable runnable) { return trying(runnable, id()); } From 18ab96a52d96935a1546d44c116f1233d30fdd4e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 15 Jul 2018 15:06:23 -0500 Subject: [PATCH 054/348] Compose#getCompose supports inference --- CHANGELOG.md | 1 + .../palatable/lambda/functor/builtin/Compose.java | 12 +++++------- .../lambda/functor/builtin/ComposeTest.java | 13 +++++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e0357890..eef1d85cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `CoProduct2-8#project` now return generalized products - `Choice2-8#project` return tuples - `liftA2` receives more parameters to aid inference +- `Compose#getCompose` now supports inference ## [3.0.3] - 2018-05-27 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index 4c4b2435f..40a732247 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -15,14 +15,14 @@ */ public final class Compose implements Applicative> { - private final Applicative, F> fga; + private final Applicative, F> fga; - public Compose(Applicative, F> fga) { + public Compose(Applicative, F> fga) { this.fga = fga; } - public Applicative, F> getCompose() { - return fga; + public , FGA extends Applicative> FGA getCompose() { + return fga.fmap(Applicative::coerce).coerce(); } @Override @@ -62,8 +62,6 @@ public int hashCode() { @Override public String toString() { - return "Compose{" + - "fga=" + fga + - '}'; + return "Compose{fga=" + fga + '}'; } } diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java index 144b71d47..3cc6198fc 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java @@ -1,11 +1,18 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static org.junit.Assert.assertEquals; + @RunWith(Traits.class) public class ComposeTest { @@ -13,4 +20,10 @@ public class ComposeTest { public Compose testSubject() { return new Compose<>(new Identity<>(new Identity<>(1))); } + + @Test + public void inference() { + Either> a = new Compose<>(right(just(1))).fmap(x -> x + 1).getCompose(); + assertEquals(right(just(2)), a); + } } \ No newline at end of file From 3490ab1aa5fbfe4588f3d9f83b9b7cbf73ca842b Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 15 Jul 2018 18:01:59 -0500 Subject: [PATCH 055/348] Adding Effect, Fn1 --- CHANGELOG.md | 4 +- .../palatable/lambda/functions/Effect.java | 54 +++++++++++++++++++ .../lambda/functions/specialized/Noop.java | 34 ++++++++++++ .../lambda/functions/EffectTest.java | 22 ++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/Effect.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index eef1d85cc..42b2d6e14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Absent`, a monoid over `Maybe` that is absence biased - `RateLimit`, a function that iterates elements from an `Iterable` according to some rate limit - `Try#withResources`, `Try`'s expression analog to Java 7's try-with-resources statement -- `Occurrences`, for counting the occurrences of the members of an `Iterable` +- `Occurrences`, for counting the occurrences of the members of an `Iterable` +- `Effect`, an `Fn0` returning `UNIT` +- `Noop`, a no-op `Effect` ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java new file mode 100644 index 000000000..62bfb941e --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -0,0 +1,54 @@ +package com.jnape.palatable.lambda.functions; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functor.Applicative; + +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; + +/** + * A function taking "no arguments", implemented as an {@link Fn1}<{@link Unit}, A>. + * + * @param the result type + * @see Fn1 + * @see Supplier + */ +@FunctionalInterface +public interface Effect extends Fn1, Consumer { + + @Override + default void accept(A a) { + apply(a); + } + + @Override + default Effect diMapL(Function fn) { + return Fn1.super.diMapL(fn)::apply; + } + + @Override + default Effect contraMap(Function fn) { + return Fn1.super.contraMap(fn)::apply; + } + + @Override + default Effect compose(Function before) { + return Fn1.super.compose(before)::apply; + } + + @Override + default Effect discardR(Applicative> appB) { + return Fn1.super.discardR(appB)::apply; + } + + @Override + default Effect andThen(Consumer after) { + return a -> { + Consumer.super.andThen(after).accept(a); + return UNIT; + }; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java new file mode 100644 index 000000000..2977f5f58 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java @@ -0,0 +1,34 @@ +package com.jnape.palatable.lambda.functions.specialized; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.Effect; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; + +/** + * As the name might suggest, this is an {@link Effect} that, *ahem*, has no effect. + * + * @param the argument type + */ +public final class Noop implements Effect { + private static final Noop INSTANCE = new Noop(); + + private Noop() { + } + + @Override + public Unit apply(A a) { + return UNIT; + } + + /** + * Static factory method that returns the singleton {@link Noop} instance. + * + * @param the argument type + * @return the singleton {@link Noop} instance + */ + @SuppressWarnings("unchecked") + public static Noop noop() { + return INSTANCE; + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java new file mode 100644 index 000000000..1b22b349b --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java @@ -0,0 +1,22 @@ +package com.jnape.palatable.lambda.functions; + +import org.junit.Test; + +import java.util.function.Consumer; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.specialized.Noop.noop; + +public class EffectTest { + + @Test + @SuppressWarnings("unused") + public void covariantReturns() { + Effect effect = noop(); + Effect diMapL = effect.diMapL(constantly("1")); + Effect contraMap = effect.contraMap(constantly("1")); + Effect compose = effect.compose(constantly("1")); + Effect stringEffect = effect.discardR(constantly("1")); + Effect andThen = effect.andThen((Consumer) noop()); + } +} \ No newline at end of file From 124a44b2948f8b44248dd2cdf8205e0560ab9e28 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 15 Jul 2018 18:13:51 -0500 Subject: [PATCH 056/348] Fn1#widen, (a -> b) -> (z -> a -> b) --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/functions/Fn1.java | 11 +++++++++++ .../com/jnape/palatable/lambda/functions/Fn2.java | 9 +++++++++ .../com/jnape/palatable/lambda/functions/Fn3.java | 9 +++++++++ .../com/jnape/palatable/lambda/functions/Fn4.java | 9 +++++++++ .../com/jnape/palatable/lambda/functions/Fn5.java | 9 +++++++++ .../com/jnape/palatable/lambda/functions/Fn6.java | 9 +++++++++ .../com/jnape/palatable/lambda/functions/Fn7.java | 9 +++++++++ .../com/jnape/palatable/lambda/functions/Fn1Test.java | 9 +++++++++ 9 files changed, 75 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42b2d6e14..8f18c3de4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Occurrences`, for counting the occurrences of the members of an `Iterable` - `Effect`, an `Fn0` returning `UNIT` - `Noop`, a no-op `Effect` +- `Fn1#widen`, add an ignored argument to the beginning of any function to raise its arity by one ### Changed - `Tuple2-8` now implement `Product2-8` diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 140206777..2d52031ce 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -8,6 +8,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** * A function taking a single argument. This is the core function type that all other function types extend and @@ -38,6 +39,16 @@ default Fn0 thunk(A a) { return __ -> apply(a); } + /** + * Widen this function's argument list by prepending an ignored argument of any type to the front. + * + * @param the new first argument type + * @return the widened function + */ + default Fn2 widen() { + return fn2(constantly(this)); + } + @Override default Fn1 flatMap(Function>> f) { return a -> f.apply(apply(a)).>coerce().apply(a); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index 543273910..9697dd884 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -7,6 +7,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn3.fn3; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** * A function taking two arguments. @@ -31,6 +32,14 @@ public interface Fn2 extends Fn1> { */ C apply(A a, B b); + /** + * @inheritDoc + */ + @Override + default Fn3 widen() { + return fn3(constantly(this)); + } + /** * Same as normal composition, except that the result is an instance of {@link Fn2} for convenience. * diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java index 7af5bb8f8..ee1fc9e0c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java @@ -7,6 +7,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn4.fn4; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** * A function taking three arguments. Defined in terms of {@link Fn2}, so similarly auto-curried. @@ -30,6 +31,14 @@ public interface Fn3 extends Fn2> { */ D apply(A a, B b, C c); + /** + * @inheritDoc + */ + @Override + default Fn4 widen() { + return fn4(constantly(this)); + } + /** * Partially apply this function by taking its first argument. * diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java index c3f48cff0..cece5bb29 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java @@ -7,6 +7,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn5.fn5; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** * A function taking four arguments. Defined in terms of {@link Fn3}, so similarly auto-curried. @@ -32,6 +33,14 @@ public interface Fn4 extends Fn3> { */ E apply(A a, B b, C c, D d); + /** + * @inheritDoc + */ + @Override + default Fn5 widen() { + return fn5(constantly(this)); + } + /** * Partially apply this function by taking its first argument. * diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java index 2d6a118ef..a1158c0ac 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java @@ -7,6 +7,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn6.fn6; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** * A function taking five arguments. Defined in terms of {@link Fn4}, so similarly auto-curried. @@ -34,6 +35,14 @@ public interface Fn5 extends Fn4> { */ F apply(A a, B b, C c, D d, E e); + /** + * @inheritDoc + */ + @Override + default Fn6 widen() { + return fn6(constantly(this)); + } + /** * Partially apply this function by taking its first argument. * diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java index cd7ca2f95..ddafbf16b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java @@ -7,6 +7,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn7.fn7; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** * A function taking six arguments. Defined in terms of {@link Fn5}, so similarly auto-curried. @@ -36,6 +37,14 @@ public interface Fn6 extends Fn5> */ G apply(A a, B b, C c, D d, E e, F f); + /** + * @inheritDoc + */ + @Override + default Fn7 widen() { + return fn7(constantly(this)); + } + /** * Partially apply this function by taking its first argument. * diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index 3e5d82354..e2942fd33 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -7,6 +7,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn8.fn8; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** * A function taking six arguments. Defined in terms of {@link Fn6}, so similarly auto-curried. @@ -38,6 +39,14 @@ public interface Fn7 extends Fn6 Fn8 widen() { + return fn8(constantly(this)); + } + /** * Partially apply this function by taking its first argument. * diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index f1e244a7c..b769d67d8 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -11,6 +11,9 @@ import java.util.function.Function; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; +import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; @RunWith(Traits.class) @@ -41,4 +44,10 @@ public void thunk() { Fn1 toString = Object::toString; assertEquals("1", toString.thunk(1).apply()); } + + @Test + public void widen() { + Fn1 addOne = x -> x + 1; + assertEquals(just(4), reduceLeft(addOne.widen().toBiFunction(), asList(1, 2, 3))); + } } From a04f781cd2f8fb88fe28ccaff5344709875dc111 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 15 Jul 2018 20:00:37 -0500 Subject: [PATCH 057/348] Ritual sacrifice to pedantic javadoc gods --- .../java/com/jnape/palatable/lambda/functions/Fn2.java | 2 +- .../java/com/jnape/palatable/lambda/functions/Fn3.java | 2 +- .../java/com/jnape/palatable/lambda/functions/Fn4.java | 2 +- .../java/com/jnape/palatable/lambda/functions/Fn5.java | 2 +- .../java/com/jnape/palatable/lambda/functions/Fn6.java | 2 +- .../java/com/jnape/palatable/lambda/functions/Fn7.java | 2 +- .../palatable/lambda/functions/builtin/fn2/LTE.java | 2 +- .../lambda/functions/builtin/fn4/RateLimit.java | 10 +++++----- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index 9697dd884..dd116a80f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -33,7 +33,7 @@ public interface Fn2 extends Fn1> { C apply(A a, B b); /** - * @inheritDoc + * {@inheritDoc} */ @Override default Fn3 widen() { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java index ee1fc9e0c..9178520dc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java @@ -32,7 +32,7 @@ public interface Fn3 extends Fn2> { D apply(A a, B b, C c); /** - * @inheritDoc + * {@inheritDoc} */ @Override default Fn4 widen() { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java index cece5bb29..4f9ea02de 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java @@ -34,7 +34,7 @@ public interface Fn4 extends Fn3> { E apply(A a, B b, C c, D d); /** - * @inheritDoc + * {@inheritDoc} */ @Override default Fn5 widen() { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java index a1158c0ac..f37f664e0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java @@ -36,7 +36,7 @@ public interface Fn5 extends Fn4> { F apply(A a, B b, C c, D d, E e); /** - * @inheritDoc + * {@inheritDoc} */ @Override default Fn6 widen() { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java index ddafbf16b..69c6619cb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java @@ -38,7 +38,7 @@ public interface Fn6 extends Fn5> G apply(A a, B b, C c, D d, E e, F f); /** - * @inheritDoc + * {@inheritDoc} */ @Override default Fn7 widen() { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index e2942fd33..90feae545 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -40,7 +40,7 @@ public interface Fn7 extends Fn6 Fn8 widen() { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java index 6e5f1f33e..8c0680cbe 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java @@ -9,7 +9,7 @@ /** * Given two {@link Comparable} values of type A, return true if the first value is less than - * or equal to the second value according to {@link Comparable#compareTo(Object);} otherwise, return false. + * or equal to the second value according to {@link Comparable#compareTo(Object)} otherwise, return false. * * @param the value typ * @see LTEBy diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java index 0b0ff5104..4c7ad843e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java @@ -21,15 +21,15 @@ *

* As an example, the following will print at most 10 elements per second: *


- * rateLimit(Clock.systemUTC()::instant, 10L, Duration.ofSeconds(1), iterate(x -> x + 1, 1)).forEach(System.out::println);
+ * rateLimit(Clock.systemUTC()::instant, 10L, Duration.ofSeconds(1), iterate(x -> x + 1, 1)).forEach(System.out::println);
  * 
* Currying allows different rate limits to be combined naturally: *

- * Iterable elements = iterate(x -> x + 1, 1);
+ * Iterable<Integer> elements = iterate(x -> x + 1, 1);
  *
- * Supplier instantSupplier = Clock.systemUTC()::instant;
- * Fn1, Iterable> tenPerSecond = rateLimit(instantSupplier, 10L, Duration.ofSeconds(1));
- * Fn1, Iterable> oneHundredEveryTwoMinutes = rateLimit(instantSupplier, 100L, Duration.ofMinutes(2));
+ * Supplier<Instant> instantSupplier = Clock.systemUTC()::instant;
+ * Fn1<Iterable<Integer>, Iterable<Integer>> tenPerSecond = rateLimit(instantSupplier, 10L, Duration.ofSeconds(1));
+ * Fn1<Iterable<Integer>, Iterable<Integer>> oneHundredEveryTwoMinutes = rateLimit(instantSupplier, 100L, Duration.ofMinutes(2));
  *
  * tenPerSecond.fmap(oneHundredEveryTwoMinutes).apply(elements).forEach(System.out::println);
  * 
From 77d6feef82dac9430f618e8a9c2148648e0e9fb0 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 16 Jul 2018 23:23:43 -0500 Subject: [PATCH 058/348] Removing deprecated members --- CHANGELOG.md | 5 +++ .../lambda/lens/lenses/CollectionLens.java | 34 ------------------- .../palatable/lambda/lens/lenses/MapLens.java | 32 ----------------- 3 files changed, 5 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f18c3de4..c49b53a53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `liftA2` receives more parameters to aid inference - `Compose#getCompose` now supports inference +### Removed +- `MapLens#mappingValues`, deprecated in a prior release +- `CollectionLens#asSet`, deprecated in a prior release +- `CollectionLens#asStream`, deprecated in a prior release + ## [3.0.3] - 2018-05-27 ### Added - `Lens#toIso`, for converting a lens to an iso diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java index 70af23f35..b43c0e596 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java @@ -31,23 +31,6 @@ public static > Lens.Simple asCopy(Function< return simpleLens(copyFn, (__, copy) -> copy); } - /** - * Convenience static factory method for creating a lens that focuses on an arbitrary {@link Collection} as a - * {@link Set}. - * - * @param the collection element type - * @param the type of the collection - * @return a lens that focuses on a Collection as a Set - * @deprecated in favor of lawful {@link CollectionLens#asSet(Function)} - */ - @Deprecated - public static > Lens.Simple> asSet() { - return simpleLens(HashSet::new, (xsL, xsS) -> { - xsL.retainAll(xsS); - return xsL; - }); - } - /** * Convenience static factory method for creating a lens that focuses on an arbitrary {@link Collection} as a * {@link Set}. @@ -69,23 +52,6 @@ public static > Lens.Simple> asSet( }); } - /** - * Convenience static factory method for creating a lens that focuses on a Collection as a Stream. - * - * @param the collection element type - * @param the type of the collection - * @return a lens that focuses on a Collection as a stream. - * @deprecated in favor of lawful {@link CollectionLens#asStream(Function)} - */ - @Deprecated - public static > Lens.Simple> asStream() { - return simpleLens(Collection::stream, (xsL, xsS) -> { - xsL.clear(); - xsS.forEach(xsL::add); - return xsL; - }); - } - /** * Convenience static factory method for creating a lens that focuses on a Collection as a Stream. *

diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java index 6da58926e..d01bfbd05 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java @@ -12,10 +12,8 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.maybe; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap; @@ -149,36 +147,6 @@ public static Lens.Simple, Map> inverted() { }); } - /** - * A lens that focuses on a map while mapping its values with the mapping function. - *

- * Note that this lens is very likely to NOT be lawful, since "you get back what you put in" will fail for all - * values B that do not map from the current values in S (new mappings cannot be - * preserved as the inversion of fn is not known). Furthermore, if fn is injective - * (multiple Vs map to the same V2), this lens will also not be lawful for similar reasons - * as stated above. - * - * @param fn the mapping function - * @param the key type - * @param the unfocused map value type - * @param the focused map value types - * @return a lens that focuses on a map while mapping its values - * @deprecated in favor of the lawful (and far more rational) {@link MapLens#mappingValues(Iso)} - */ - @Deprecated - public static Lens.Simple, Map> mappingValues(Function fn) { - return simpleLens(m -> toMap(HashMap::new, map(t -> t.biMapR(fn), map(Tuple2::fromEntry, m.entrySet()))), - (s, b) -> { - Set retainKeys = Filter.>filter(kv -> eq(fn.apply(kv.getValue()), b.get(kv.getKey()))) - .andThen(map(Map.Entry::getKey)) - .andThen(toCollection(HashSet::new)) - .apply(s.entrySet()); - Map copy = new HashMap<>(s); - copy.keySet().retainAll(retainKeys); - return copy; - }); - } - /** * A lens that focuses on a map while mapping its values with the mapping {@link Iso}. *

From 4b37b97102c72ea5688387d4f56f64926b44522f Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 16 Jul 2018 23:28:52 -0500 Subject: [PATCH 059/348] [maven-release-plugin] prepare release lambda-3.1.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a993aac9b..6f0a6e0aa 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.0.4-SNAPSHOT + 3.1.0 jar Lambda From c786ff840e9de781fc2121ce6529576f914378b9 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 16 Jul 2018 23:28:57 -0500 Subject: [PATCH 060/348] [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 6f0a6e0aa..94275b818 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.1.0 + 3.1.1-SNAPSHOT jar Lambda From a2c084c0b7f22c73f0c3c8a73fc96eed2ca2fd5e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 22 Jul 2018 17:16:06 -0500 Subject: [PATCH 061/348] Updating README and CHANGELOG to reflect latest version --- CHANGELOG.md | 6 +++++- README.md | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c49b53a53..286016b8a 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 changes yet_ + +## [3.1.0] - 2018-07-16 ### Added - `Fn3-8` static factory overloads to aid in coercing lambdas - Adding composition guarantees to `LensLike` @@ -368,7 +371,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.3...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-3.1.0...HEAD +[3.1.0]: https://github.com/palatable/lambda/compare/lambda-3.0.3...lambda-3.1.0 [3.0.3]: https://github.com/palatable/lambda/compare/lambda-3.0.2...lambda-3.0.3 [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 diff --git a/README.md b/README.md index 13892496a..1d2dc60b0 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 3.0.3 + 3.1.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '3.0.3' +compile group: 'com.jnape.palatable', name: 'lambda', version: '3.1.0' ``` Examples From 00c35f703db1c26f09f51d44b8e0dca87086895c Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 28 Jul 2018 15:22:36 -0500 Subject: [PATCH 062/348] Difference and Intersection were never meant to implement Semigroup. Time for semigroup assertion helpers. --- CHANGELOG.md | 3 ++- .../builtin => functions/builtin/fn2}/Difference.java | 6 +++--- .../builtin => functions/builtin/fn2}/Intersection.java | 6 +++--- .../builtin => functions/builtin/fn2}/DifferenceTest.java | 4 ++-- .../builtin => functions/builtin/fn2}/IntersectionTest.java | 4 ++-- 5 files changed, 12 insertions(+), 11 deletions(-) rename src/main/java/com/jnape/palatable/lambda/{semigroup/builtin => functions/builtin/fn2}/Difference.java (90%) rename src/main/java/com/jnape/palatable/lambda/{semigroup/builtin => functions/builtin/fn2}/Intersection.java (89%) rename src/test/java/com/jnape/palatable/lambda/{semigroup/builtin => functions/builtin/fn2}/DifferenceTest.java (91%) rename src/test/java/com/jnape/palatable/lambda/{semigroup/builtin => functions/builtin/fn2}/IntersectionTest.java (92%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 286016b8a..007ec4552 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 changes yet_ +### Changed +- ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to `functions.builtin.fn2` package ## [3.1.0] - 2018-07-16 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Difference.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java similarity index 90% rename from src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Difference.java rename to src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java index b1df01f77..777279597 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Difference.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java @@ -1,8 +1,8 @@ -package com.jnape.palatable.lambda.semigroup.builtin; +package com.jnape.palatable.lambda.functions.builtin.fn2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct; -import com.jnape.palatable.lambda.semigroup.Semigroup; import java.util.HashSet; @@ -21,7 +21,7 @@ * * @param the {@link Iterable} element type */ -public final class Difference implements Semigroup> { +public final class Difference implements Fn2, Iterable, Iterable> { private static final Difference INSTANCE = new Difference(); diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java similarity index 89% rename from src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java rename to src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java index 044763f83..1124ce61f 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java @@ -1,8 +1,8 @@ -package com.jnape.palatable.lambda.semigroup.builtin; +package com.jnape.palatable.lambda.functions.builtin.fn2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct; -import com.jnape.palatable.lambda.semigroup.Semigroup; import java.util.HashSet; import java.util.Set; @@ -19,7 +19,7 @@ * * @param the {@link Iterable} element type */ -public final class Intersection implements Semigroup> { +public final class Intersection implements Fn2, Iterable, Iterable> { private static final Intersection INSTANCE = new Intersection(); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/DifferenceTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/DifferenceTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/semigroup/builtin/DifferenceTest.java rename to src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/DifferenceTest.java index 929a2b9f8..2b1dd6ecc 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/DifferenceTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/DifferenceTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.semigroup.builtin; +package com.jnape.palatable.lambda.functions.builtin.fn2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -11,7 +11,7 @@ import testsupport.traits.InfiniteIterableSupport; import testsupport.traits.Laziness; -import static com.jnape.palatable.lambda.semigroup.builtin.Difference.difference; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Difference.difference; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersectionTest.java similarity index 92% rename from src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java rename to src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersectionTest.java index 0ecd33c71..13c16ace3 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersectionTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.semigroup.builtin; +package com.jnape.palatable.lambda.functions.builtin.fn2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -10,7 +10,7 @@ import testsupport.traits.InfiniteIterableSupport; import testsupport.traits.Laziness; -import static com.jnape.palatable.lambda.semigroup.builtin.Intersection.intersection; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Intersection.intersection; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; From 9e517426974a90f44c23b0a5606529ffc775241f Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 28 Jul 2018 15:24:48 -0500 Subject: [PATCH 063/348] Better implementation of Intersection --- .../lambda/functions/builtin/fn2/Intersection.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java index 1124ce61f..178b7be8c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java @@ -4,9 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct; -import java.util.HashSet; -import java.util.Set; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; @@ -28,8 +25,7 @@ private Intersection() { @Override public Iterable apply(Iterable xs, Iterable ys) { - Set seen = new HashSet<>(); - return distinct(filter(a -> seen.contains(a) || find(eq(a), ys).peek(seen::add).fmap(constantly(true)).orElse(false), xs)); + return filter(x -> find(eq(x), ys).fmap(constantly(true)).orElse(false), distinct(xs)); } @SuppressWarnings("unchecked") From 7d5ff797636461567b25ede718857876234aa12f Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 31 Jul 2018 20:36:06 -0500 Subject: [PATCH 064/348] Moving Absent to semigroups --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/monoid/builtin/Present.java | 1 + .../lambda/{monoid => semigroup}/builtin/Absent.java | 3 ++- .../lambda/{monoid => semigroup}/builtin/AbsentTest.java | 6 +++--- 4 files changed, 7 insertions(+), 4 deletions(-) rename src/main/java/com/jnape/palatable/lambda/{monoid => semigroup}/builtin/Absent.java (94%) rename src/test/java/com/jnape/palatable/lambda/{monoid => semigroup}/builtin/AbsentTest.java (81%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 007ec4552..9ba882791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Changed - ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to `functions.builtin.fn2` package +- ***Breaking Change***: `Absent` moved to `semigroup.builtin` package ## [3.1.0] - 2018-07-16 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java index af2a51ee5..cccf15d1b 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; import com.jnape.palatable.lambda.monoid.Monoid; import com.jnape.palatable.lambda.semigroup.Semigroup; +import com.jnape.palatable.lambda.semigroup.builtin.Absent; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.monoid.Monoid.monoid; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java similarity index 94% rename from src/main/java/com/jnape/palatable/lambda/monoid/builtin/Absent.java rename to src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java index db38aad3e..9c5392860 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Absent.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java @@ -1,9 +1,10 @@ -package com.jnape.palatable.lambda.monoid.builtin; +package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn3.LiftA2; import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.lambda.semigroup.Semigroup; /** diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AbsentTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java similarity index 81% rename from src/test/java/com/jnape/palatable/lambda/monoid/builtin/AbsentTest.java rename to src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java index 6a0196daa..7df46e6e2 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AbsentTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java @@ -1,17 +1,17 @@ -package com.jnape.palatable.lambda.monoid.builtin; +package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.semigroup.Semigroup; 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.monoid.builtin.Absent.absent; +import static com.jnape.palatable.lambda.semigroup.builtin.Absent.absent; import static org.junit.Assert.assertEquals; public class AbsentTest { @Test - public void monoid() { + public void semigroup() { Absent absent = absent(); Semigroup addition = (x, y) -> x + y; From 24949f16a911ca81eefbae19534137b6abde1ad2 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 1 Aug 2018 21:55:31 -0500 Subject: [PATCH 065/348] RightAny returns a Monoid --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/monoid/builtin/RightAny.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ba882791..9553f995b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to `functions.builtin.fn2` package - ***Breaking Change***: `Absent` moved to `semigroup.builtin` package +- `RightAny` overload returns `Monoid` ## [3.1.0] - 2018-07-16 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java index ad812cffd..f357d5da4 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java @@ -45,7 +45,7 @@ public static RightAny rightAny() { return INSTANCE; } - public static Semigroup> rightAny(Monoid rMonoid) { + public static Monoid> rightAny(Monoid rMonoid) { return RightAny.rightAny().apply(rMonoid); } From fc83731365d9dd7aa9f91e0a15412584b2a56d25 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 1 Aug 2018 22:28:42 -0500 Subject: [PATCH 066/348] Product2#invert and static factory method --- .../lambda/adt/product/Product2.java | 32 +++++++++++++++++++ .../lambda/adt/product/Product2Test.java | 23 +++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 src/test/java/com/jnape/palatable/lambda/adt/product/Product2Test.java diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java index e9619203b..8b44cf309 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java @@ -43,6 +43,15 @@ default R into(BiFunction fn) { return fn.apply(_1(), _2()); } + /** + * Flip the slots of this {@link Product2}. + * + * @return the flipped {@link Product2} + */ + default Product2<_2, _1> invert() { + return into((_1, _2) -> product(_2, _1)); + } + @Override default _1 getKey() { return _1(); @@ -57,4 +66,27 @@ default _2 getValue() { default _2 setValue(_2 value) { throw new UnsupportedOperationException(); } + + /** + * Static factory method for creating a generic {@link Product2}. + * + * @param _1 the first slot + * @param _2 the second slot + * @param <_1> the first slot type + * @param <_2> the second slot type + * @return the {@link Product2} + */ + static <_1, _2> Product2<_1, _2> product(_1 _1, _2 _2) { + return new Product2<_1, _2>() { + @Override + public _1 _1() { + return _1; + } + + @Override + public _2 _2() { + return _2; + } + }; + } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/product/Product2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/product/Product2Test.java new file mode 100644 index 000000000..d094cd39d --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/adt/product/Product2Test.java @@ -0,0 +1,23 @@ +package com.jnape.palatable.lambda.adt.product; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.product.Product2.product; +import static org.junit.Assert.assertEquals; + +public class Product2Test { + + @Test + public void staticFactoryMethod() { + Product2 product = product("a", "b"); + assertEquals("a", product._1()); + assertEquals("b", product._2()); + } + + @Test + public void invert() { + Product2 inverted = product("a", "b").invert(); + assertEquals("b", inverted._1()); + assertEquals("a", inverted._2()); + } +} \ No newline at end of file From e86e212811a7dcc3c6ef08bf6407d22ae72d28ca Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 2 Aug 2018 22:51:13 -0500 Subject: [PATCH 067/348] Adding predicate static factory method --- CHANGELOG.md | 3 +++ .../lambda/functions/specialized/Predicate.java | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9553f995b..cbee0a87b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - ***Breaking Change***: `Absent` moved to `semigroup.builtin` package - `RightAny` overload returns `Monoid` +### Added +- `Predicate#predicate` static factory method + ## [3.1.0] - 2018-07-16 ### Added - `Fn3-8` static factory overloads to aid in coercing lambdas diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java index 89e3e5e93..a9d0de708 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java @@ -82,4 +82,15 @@ default Predicate or(java.util.function.Predicate other) { default Predicate negate() { return a -> !apply(a); } + + /** + * Static factory method to create a predicate from a function. + * + * @param predicate the function + * @param the input type + * @return the predicate + */ + static Predicate predicate(Function predicate) { + return predicate::apply; + } } From c1c4893246f3f7e083b0e216f1078b4ea89959f8 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 4 Aug 2018 17:43:55 -0500 Subject: [PATCH 068/348] Product invert/rotateL/R cardinality variants with tuple specializations --- CHANGELOG.md | 2 + .../palatable/lambda/adt/hlist/Tuple2.java | 5 + .../palatable/lambda/adt/hlist/Tuple3.java | 15 ++ .../palatable/lambda/adt/hlist/Tuple4.java | 34 ++++- .../palatable/lambda/adt/hlist/Tuple5.java | 35 +++++ .../palatable/lambda/adt/hlist/Tuple6.java | 45 ++++++ .../palatable/lambda/adt/hlist/Tuple7.java | 55 +++++++ .../palatable/lambda/adt/hlist/Tuple8.java | 65 ++++++++ .../lambda/adt/product/Product2.java | 4 +- .../lambda/adt/product/Product3.java | 53 +++++++ .../lambda/adt/product/Product4.java | 70 +++++++++ .../lambda/adt/product/Product5.java | 87 +++++++++++ .../lambda/adt/product/Product6.java | 105 +++++++++++++ .../lambda/adt/product/Product7.java | 122 +++++++++++++++ .../lambda/adt/product/Product8.java | 140 ++++++++++++++++++ .../lambda/adt/product/Product2Test.java | 13 +- .../lambda/adt/product/Product3Test.java | 31 ++++ .../lambda/adt/product/Product4Test.java | 34 +++++ .../lambda/adt/product/Product5Test.java | 37 +++++ .../lambda/adt/product/Product6Test.java | 40 +++++ .../lambda/adt/product/Product7Test.java | 43 ++++++ .../lambda/adt/product/Product8Test.java | 46 ++++++ 22 files changed, 1069 insertions(+), 12 deletions(-) create mode 100644 src/test/java/com/jnape/palatable/lambda/adt/product/Product3Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/adt/product/Product4Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/adt/product/Product5Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/adt/product/Product6Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/adt/product/Product7Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/adt/product/Product8Test.java diff --git a/CHANGELOG.md b/CHANGELOG.md index cbee0a87b..baf77d010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `Predicate#predicate` static factory method +- `Product2-8` left/right rotation methods +- `Tuple2-8` specializations of left/right product rotation ## [3.1.0] - 2018-07-16 ### Added 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 f59f77d71..621537198 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 @@ -70,6 +70,11 @@ public _2 setValue(_2 value) { throw new UnsupportedOperationException(); } + @Override + public Tuple2<_2, _1> invert() { + return tuple(_2, _1); + } + @Override public <_2Prime> Tuple2<_1, _2Prime> fmap(Function fn) { return Monad.super.<_2Prime>fmap(fn).coerce(); 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 235b5bf30..32d8a5359 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 @@ -61,6 +61,21 @@ public _3 _3() { return _3; } + @Override + public Tuple3<_2, _3, _1> rotateL3() { + return tuple(_2, _3, _1); + } + + @Override + public Tuple3<_3, _1, _2> rotateR3() { + return tuple(_3, _1, _2); + } + + @Override + public Tuple3<_2, _1, _3> invert() { + return tuple(_2, _1, _3); + } + @Override @SuppressWarnings("unchecked") public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Function fn) { 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 f24d1cca2..af141c9f3 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 @@ -70,21 +70,43 @@ public _4 _4() { } @Override - @SuppressWarnings("unchecked") + public Tuple4<_2, _3, _4, _1> rotateL4() { + return tuple(_2, _3, _4, _1); + } + + @Override + public Tuple4<_4, _1, _2, _3> rotateR4() { + return tuple(_4, _1, _2, _3); + } + + @Override + public Tuple4<_2, _3, _1, _4> rotateL3() { + return tuple(_2, _3, _1, _4); + } + + @Override + public Tuple4<_3, _1, _2, _4> rotateR3() { + return tuple(_3, _1, _2, _4); + } + + @Override + public Tuple4<_2, _1, _3, _4> invert() { + return tuple(_2, _1, _3, _4); + } + + @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(Function fn) { - return (Tuple4<_1, _2, _3, _4Prime>) Monad.super.fmap(fn); + return (Tuple4<_1, _2, _3, _4Prime>) Monad.super.<_4Prime>fmap(fn); } @Override - @SuppressWarnings("unchecked") public <_3Prime> Tuple4<_1, _2, _3Prime, _4> biMapL(Function fn) { - return (Tuple4<_1, _2, _3Prime, _4>) Bifunctor.super.biMapL(fn); + return (Tuple4<_1, _2, _3Prime, _4>) Bifunctor.super.<_3Prime>biMapL(fn); } @Override - @SuppressWarnings("unchecked") public <_4Prime> Tuple4<_1, _2, _3, _4Prime> biMapR(Function fn) { - return (Tuple4<_1, _2, _3, _4Prime>) Bifunctor.super.biMapR(fn); + return (Tuple4<_1, _2, _3, _4Prime>) Bifunctor.super.<_4Prime>biMapR(fn); } @Override 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 9936cc243..65dfb3c7a 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 @@ -77,6 +77,41 @@ public _5 _5() { return _5; } + @Override + public Tuple5<_2, _3, _4, _5, _1> rotateL5() { + return tuple(_2, _3, _4, _5, _1); + } + + @Override + public Tuple5<_5, _1, _2, _3, _4> rotateR5() { + return tuple(_5, _1, _2, _3, _4); + } + + @Override + public Tuple5<_2, _3, _4, _1, _5> rotateL4() { + return tuple(_2, _3, _4, _1, _5); + } + + @Override + public Tuple5<_4, _1, _2, _3, _5> rotateR4() { + return tuple(_4, _1, _2, _3, _5); + } + + @Override + public Tuple5<_2, _3, _1, _4, _5> rotateL3() { + return tuple(_2, _3, _1, _4, _5); + } + + @Override + public Tuple5<_3, _1, _2, _4, _5> rotateR3() { + return tuple(_3, _1, _2, _4, _5); + } + + @Override + public Tuple5<_2, _1, _3, _4, _5> invert() { + return tuple(_2, _1, _3, _4, _5); + } + @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Function fn) { return Monad.super.<_5Prime>fmap(fn).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 1cdbbb343..0f3046ace 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -86,6 +86,51 @@ public _6 _6() { return _6; } + @Override + public Tuple6<_2, _3, _4, _5, _6, _1> rotateL6() { + return tuple(_2, _3, _4, _5, _6, _1); + } + + @Override + public Tuple6<_6, _1, _2, _3, _4, _5> rotateR6() { + return tuple(_6, _1, _2, _3, _4, _5); + } + + @Override + public Tuple6<_2, _3, _4, _5, _1, _6> rotateL5() { + return tuple(_2, _3, _4, _5, _1, _6); + } + + @Override + public Tuple6<_5, _1, _2, _3, _4, _6> rotateR5() { + return tuple(_5, _1, _2, _3, _4, _6); + } + + @Override + public Tuple6<_2, _3, _4, _1, _5, _6> rotateL4() { + return tuple(_2, _3, _4, _1, _5, _6); + } + + @Override + public Tuple6<_4, _1, _2, _3, _5, _6> rotateR4() { + return tuple(_4, _1, _2, _3, _5, _6); + } + + @Override + public Tuple6<_2, _3, _1, _4, _5, _6> rotateL3() { + return tuple(_2, _3, _1, _4, _5, _6); + } + + @Override + public Tuple6<_3, _1, _2, _4, _5, _6> rotateR3() { + return tuple(_3, _1, _2, _4, _5, _6); + } + + @Override + public Tuple6<_2, _1, _3, _4, _5, _6> invert() { + return tuple(_2, _1, _3, _4, _5, _6); + } + @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> fmap(Function fn) { return Monad.super.<_6Prime>fmap(fn).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index 439137c20..1910381d1 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -95,6 +95,61 @@ public _7 _7() { return _7; } + @Override + public Tuple7<_2, _3, _4, _5, _6, _7, _1> rotateL7() { + return tuple(_2, _3, _4, _5, _6, _7, _1); + } + + @Override + public Tuple7<_7, _1, _2, _3, _4, _5, _6> rotateR7() { + return tuple(_7, _1, _2, _3, _4, _5, _6); + } + + @Override + public Tuple7<_2, _3, _4, _5, _6, _1, _7> rotateL6() { + return tuple(_2, _3, _4, _5, _6, _1, _7); + } + + @Override + public Tuple7<_6, _1, _2, _3, _4, _5, _7> rotateR6() { + return tuple(_6, _1, _2, _3, _4, _5, _7); + } + + @Override + public Tuple7<_2, _3, _4, _5, _1, _6, _7> rotateL5() { + return tuple(_2, _3, _4, _5, _1, _6, _7); + } + + @Override + public Tuple7<_5, _1, _2, _3, _4, _6, _7> rotateR5() { + return tuple(_5, _1, _2, _3, _4, _6, _7); + } + + @Override + public Tuple7<_2, _3, _4, _1, _5, _6, _7> rotateL4() { + return tuple(_2, _3, _4, _1, _5, _6, _7); + } + + @Override + public Tuple7<_4, _1, _2, _3, _5, _6, _7> rotateR4() { + return tuple(_4, _1, _2, _3, _5, _6, _7); + } + + @Override + public Tuple7<_2, _3, _1, _4, _5, _6, _7> rotateL3() { + return tuple(_2, _3, _1, _4, _5, _6, _7); + } + + @Override + public Tuple7<_3, _1, _2, _4, _5, _6, _7> rotateR3() { + return tuple(_3, _1, _2, _4, _5, _6, _7); + } + + @Override + public Tuple7<_2, _1, _3, _4, _5, _6, _7> invert() { + return tuple(_2, _1, _3, _4, _5, _6, _7); + } + @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> fmap(Function fn) { return Monad.super.<_7Prime>fmap(fn).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 63b0279f4..30a9eba61 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -104,6 +104,71 @@ public _8 _8() { return _8; } + @Override + public Tuple8<_2, _3, _4, _5, _6, _7, _8, _1> rotateL8() { + return tuple(_2, _3, _4, _5, _6, _7, _8, _1); + } + + @Override + public Tuple8<_8, _1, _2, _3, _4, _5, _6, _7> rotateR8() { + return tuple(_8, _1, _2, _3, _4, _5, _6, _7); + } + + @Override + public Tuple8<_2, _3, _4, _5, _6, _7, _1, _8> rotateL7() { + return tuple(_2, _3, _4, _5, _6, _7, _1, _8); + } + + @Override + public Tuple8<_7, _1, _2, _3, _4, _5, _6, _8> rotateR7() { + return tuple(_7, _1, _2, _3, _4, _5, _6, _8); + } + + @Override + public Tuple8<_2, _3, _4, _5, _6, _1, _7, _8> rotateL6() { + return tuple(_2, _3, _4, _5, _6, _1, _7, _8); + } + + @Override + public Tuple8<_6, _1, _2, _3, _4, _5, _7, _8> rotateR6() { + return tuple(_6, _1, _2, _3, _4, _5, _7, _8); + } + + @Override + public Tuple8<_2, _3, _4, _5, _1, _6, _7, _8> rotateL5() { + return tuple(_2, _3, _4, _5, _1, _6, _7, _8); + } + + @Override + public Tuple8<_5, _1, _2, _3, _4, _6, _7, _8> rotateR5() { + return tuple(_5, _1, _2, _3, _4, _6, _7, _8); + } + + @Override + public Tuple8<_2, _3, _4, _1, _5, _6, _7, _8> rotateL4() { + return tuple(_2, _3, _4, _1, _5, _6, _7, _8); + } + + @Override + public Tuple8<_4, _1, _2, _3, _5, _6, _7, _8> rotateR4() { + return tuple(_4, _1, _2, _3, _5, _6, _7, _8); + } + + @Override + public Tuple8<_2, _3, _1, _4, _5, _6, _7, _8> rotateL3() { + return tuple(_2, _3, _1, _4, _5, _6, _7, _8); + } + + @Override + public Tuple8<_3, _1, _2, _4, _5, _6, _7, _8> rotateR3() { + return tuple(_3, _1, _2, _4, _5, _6, _7, _8); + } + + @Override + public Tuple8<_2, _1, _3, _4, _5, _6, _7, _8> invert() { + return tuple(_2, _1, _3, _4, _5, _6, _7, _8); + } + @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> fmap(Function fn) { return Monad.super.<_8Prime>fmap(fn).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java index 8b44cf309..4c3d64da0 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java @@ -44,9 +44,9 @@ default R into(BiFunction fn) { } /** - * Flip the slots of this {@link Product2}. + * Rotate the first two slots of this product. * - * @return the flipped {@link Product2} + * @return the rotated product */ default Product2<_2, _1> invert() { return into((_1, _2) -> product(_2, _1)); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java index 241c97c5f..063456453 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java @@ -32,4 +32,57 @@ public interface Product3<_1, _2, _3> extends Product2<_1, _2> { default R into(Fn3 fn) { return Product2.super.into(fn.toBiFunction()).apply(_3()); } + + /** + * Rotate the first three values of this product one slot to the left. + * + * @return the left-rotated product + */ + default Product3<_2, _3, _1> rotateL3() { + return into((_1, _2, _3) -> product(_2, _3, _1)); + } + + /** + * Rotate the first three values of this product one slot to the right. + * + * @return the right-rotated product + */ + default Product3<_3, _1, _2> rotateR3() { + return into((_1, _2, _3) -> product(_3, _1, _2)); + } + + @Override + default Product3<_2, _1, _3> invert() { + return into((_1, _2, _3) -> product(_2, _1, _3)); + } + + /** + * Static factory method for creating a generic {@link Product3}. + * + * @param _1 the first slot + * @param _2 the second slot + * @param _3 the third slot + * @param <_1> the first slot type + * @param <_2> the second slot type + * @param <_3> the third slot type + * @return the {@link Product3} + */ + static <_1, _2, _3> Product3<_1, _2, _3> product(_1 _1, _2 _2, _3 _3) { + return new Product3<_1, _2, _3>() { + @Override + public _1 _1() { + return _1; + } + + @Override + public _2 _2() { + return _2; + } + + @Override + public _3 _3() { + return _3; + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java index 554591ed5..2703f8229 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java @@ -33,4 +33,74 @@ public interface Product4<_1, _2, _3, _4> extends Product3<_1, _2, _3> { default R into(Fn4 fn) { return Product3.super.into(fn).apply(_4()); } + + /** + * Rotate the first four values of this product one slot to the left. + * + * @return the left-rotated product + */ + default Product4<_2, _3, _4, _1> rotateL4() { + return into((_1, _2, _3, _4) -> product(_2, _3, _4, _1)); + } + + /** + * Rotate the first four values of this product one slot to the right. + * + * @return the right-rotated product + */ + default Product4<_4, _1, _2, _3> rotateR4() { + return into((_1, _2, _3, _4) -> product(_4, _1, _2, _3)); + } + + @Override + default Product4<_2, _3, _1, _4> rotateL3() { + return into((_1, _2, _3, _4) -> product(_2, _3, _1, _4)); + } + + @Override + default Product4<_3, _1, _2, _4> rotateR3() { + return into((_1, _2, _3, _4) -> product(_3, _1, _2, _4)); + } + + @Override + default Product4<_2, _1, _3, _4> invert() { + return into((_1, _2, _3, _4) -> product(_2, _1, _3, _4)); + } + + /** + * Static factory method for creating a generic {@link Product4}. + * + * @param _1 the first slot + * @param _2 the second slot + * @param _3 the third slot + * @param _4 the fourth slot + * @param <_1> the first slot type + * @param <_2> the second slot type + * @param <_3> the third slot type + * @param <_4> the fourth slot type + * @return the {@link Product4} + */ + static <_1, _2, _3, _4> Product4<_1, _2, _3, _4> product(_1 _1, _2 _2, _3 _3, _4 _4) { + return new Product4<_1, _2, _3, _4>() { + @Override + public _1 _1() { + return _1; + } + + @Override + public _2 _2() { + return _2; + } + + @Override + public _3 _3() { + return _3; + } + + @Override + public _4 _4() { + return _4; + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product5.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product5.java index 144fc296c..864671bbe 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product5.java @@ -35,4 +35,91 @@ public interface Product5<_1, _2, _3, _4, _5> extends Product4<_1, _2, _3, _4> { default R into(Fn5 fn) { return Product4.super.>into(fn).apply(_5()); } + + /** + * Rotate the first five values of this product one slot to the left. + * + * @return the left-rotated product + */ + default Product5<_2, _3, _4, _5, _1> rotateL5() { + return into((_1, _2, _3, _4, _5) -> product(_2, _3, _4, _5, _1)); + } + + /** + * Rotate the first five values of this product one slot to the right. + * + * @return the right-rotated product + */ + default Product5<_5, _1, _2, _3, _4> rotateR5() { + return into((_1, _2, _3, _4, _5) -> product(_5, _1, _2, _3, _4)); + } + + @Override + default Product5<_2, _3, _4, _1, _5> rotateL4() { + return into((_1, _2, _3, _4, _5) -> product(_2, _3, _4, _1, _5)); + } + + @Override + default Product5<_4, _1, _2, _3, _5> rotateR4() { + return into((_1, _2, _3, _4, _5) -> product(_4, _1, _2, _3, _5)); + } + + @Override + default Product5<_2, _3, _1, _4, _5> rotateL3() { + return into((_1, _2, _3, _4, _5) -> product(_2, _3, _1, _4, _5)); + } + + @Override + default Product5<_3, _1, _2, _4, _5> rotateR3() { + return into((_1, _2, _3, _4, _5) -> product(_3, _1, _2, _4, _5)); + } + + @Override + default Product5<_2, _1, _3, _4, _5> invert() { + return into((_1, _2, _3, _4, _5) -> product(_2, _1, _3, _4, _5)); + } + + /** + * Static factory method for creating a generic {@link Product5}. + * + * @param _1 the first slot + * @param _2 the second slot + * @param _3 the third slot + * @param _4 the fourth slot + * @param _5 the fifth slot + * @param <_1> the first slot type + * @param <_2> the second slot type + * @param <_3> the third slot type + * @param <_4> the fourth slot type + * @param <_5> the fifth slot type + * @return the {@link Product5} + */ + static <_1, _2, _3, _4, _5> Product5<_1, _2, _3, _4, _5> product(_1 _1, _2 _2, _3 _3, _4 _4, _5 _5) { + return new Product5<_1, _2, _3, _4, _5>() { + @Override + public _1 _1() { + return _1; + } + + @Override + public _2 _2() { + return _2; + } + + @Override + public _3 _3() { + return _3; + } + + @Override + public _4 _4() { + return _4; + } + + @Override + public _5 _5() { + return _5; + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product6.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product6.java index 07b14a307..2ea16a9a5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product6.java @@ -36,4 +36,109 @@ public interface Product6<_1, _2, _3, _4, _5, _6> extends Product5<_1, _2, _3, _ default R into(Fn6 fn) { return Product5.super.>into(fn).apply(_6()); } + + /** + * Rotate the first six values of this product one slot to the left. + * + * @return the left-rotated product + */ + default Product6<_2, _3, _4, _5, _6, _1> rotateL6() { + return into((_1, _2, _3, _4, _5, _6) -> product(_2, _3, _4, _5, _6, _1)); + } + + /** + * Rotate the first six values of this product one slot to the right. + * + * @return the right-rotated product + */ + default Product6<_6, _1, _2, _3, _4, _5> rotateR6() { + return into((_1, _2, _3, _4, _5, _6) -> product(_6, _1, _2, _3, _4, _5)); + } + + @Override + default Product6<_2, _3, _4, _5, _1, _6> rotateL5() { + return into((_1, _2, _3, _4, _5, _6) -> product(_2, _3, _4, _5, _1, _6)); + } + + @Override + default Product6<_5, _1, _2, _3, _4, _6> rotateR5() { + return into((_1, _2, _3, _4, _5, _6) -> product(_5, _1, _2, _3, _4, _6)); + } + + @Override + default Product6<_2, _3, _4, _1, _5, _6> rotateL4() { + return into((_1, _2, _3, _4, _5, _6) -> product(_2, _3, _4, _1, _5, _6)); + } + + @Override + default Product6<_4, _1, _2, _3, _5, _6> rotateR4() { + return into((_1, _2, _3, _4, _5, _6) -> product(_4, _1, _2, _3, _5, _6)); + } + + @Override + default Product6<_2, _3, _1, _4, _5, _6> rotateL3() { + return into((_1, _2, _3, _4, _5, _6) -> product(_2, _3, _1, _4, _5, _6)); + } + + @Override + default Product6<_3, _1, _2, _4, _5, _6> rotateR3() { + return into((_1, _2, _3, _4, _5, _6) -> product(_3, _1, _2, _4, _5, _6)); + } + + @Override + default Product6<_2, _1, _3, _4, _5, _6> invert() { + return into((_1, _2, _3, _4, _5, _6) -> product(_2, _1, _3, _4, _5, _6)); + } + + /** + * Static factory method for creating a generic {@link Product6}. + * + * @param _1 the first slot + * @param _2 the second slot + * @param _3 the third slot + * @param _4 the fourth slot + * @param _5 the fifth slot + * @param _6 the sixth slot + * @param <_1> the first slot type + * @param <_2> the second slot type + * @param <_3> the third slot type + * @param <_4> the fourth slot type + * @param <_5> the fifth slot type + * @param <_6> the sixth slot type + * @return the {@link Product6} + */ + static <_1, _2, _3, _4, _5, _6> Product6<_1, _2, _3, _4, _5, _6> product(_1 _1, _2 _2, _3 _3, _4 _4, _5 _5, + _6 _6) { + return new Product6<_1, _2, _3, _4, _5, _6>() { + @Override + public _1 _1() { + return _1; + } + + @Override + public _2 _2() { + return _2; + } + + @Override + public _3 _3() { + return _3; + } + + @Override + public _4 _4() { + return _4; + } + + @Override + public _5 _5() { + return _5; + } + + @Override + public _6 _6() { + return _6; + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product7.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product7.java index 0ea905148..75b9fc1d8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product7.java @@ -38,4 +38,126 @@ default R into( Fn7 fn) { return Product6.super.>into(fn).apply(_7()); } + + /** + * Rotate the first seven values of this product one slot to the left. + * + * @return the left-rotated product + */ + default Product7<_2, _3, _4, _5, _6, _7, _1> rotateL7() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_2, _3, _4, _5, _6, _7, _1)); + } + + /** + * Rotate the first seven values of this product one slot to the right. + * + * @return the right-rotated product + */ + default Product7<_7, _1, _2, _3, _4, _5, _6> rotateR7() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_7, _1, _2, _3, _4, _5, _6)); + } + + @Override + default Product7<_2, _3, _4, _5, _6, _1, _7> rotateL6() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_2, _3, _4, _5, _6, _1, _7)); + } + + @Override + default Product7<_6, _1, _2, _3, _4, _5, _7> rotateR6() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_6, _1, _2, _3, _4, _5, _7)); + } + + @Override + default Product7<_2, _3, _4, _5, _1, _6, _7> rotateL5() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_2, _3, _4, _5, _1, _6, _7)); + } + + @Override + default Product7<_5, _1, _2, _3, _4, _6, _7> rotateR5() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_5, _1, _2, _3, _4, _6, _7)); + } + + @Override + default Product7<_2, _3, _4, _1, _5, _6, _7> rotateL4() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_2, _3, _4, _1, _5, _6, _7)); + } + + @Override + default Product7<_4, _1, _2, _3, _5, _6, _7> rotateR4() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_4, _1, _2, _3, _5, _6, _7)); + } + + @Override + default Product7<_2, _3, _1, _4, _5, _6, _7> rotateL3() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_2, _3, _1, _4, _5, _6, _7)); + } + + @Override + default Product7<_3, _1, _2, _4, _5, _6, _7> rotateR3() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_3, _1, _2, _4, _5, _6, _7)); + } + + @Override + default Product7<_2, _1, _3, _4, _5, _6, _7> invert() { + return into((_1, _2, _3, _4, _5, _6, _7) -> product(_2, _1, _3, _4, _5, _6, _7)); + } + + /** + * Static factory method for creating a generic {@link Product7}. + * + * @param _1 the first slot + * @param _2 the second slot + * @param _3 the third slot + * @param _4 the fourth slot + * @param _5 the fifth slot + * @param _6 the sixth slot + * @param _7 the seventh slot + * @param <_1> the first slot type + * @param <_2> the second slot type + * @param <_3> the third slot type + * @param <_4> the fourth slot type + * @param <_5> the fifth slot type + * @param <_6> the sixth slot type + * @param <_7> the seventh slot type + * @return the {@link Product7} + */ + static <_1, _2, _3, _4, _5, _6, _7> Product7<_1, _2, _3, _4, _5, _6, _7> product(_1 _1, _2 _2, _3 _3, _4 _4, _5 _5, + _6 _6, _7 _7) { + return new Product7<_1, _2, _3, _4, _5, _6, _7>() { + @Override + public _1 _1() { + return _1; + } + + @Override + public _2 _2() { + return _2; + } + + @Override + public _3 _3() { + return _3; + } + + @Override + public _4 _4() { + return _4; + } + + @Override + public _5 _5() { + return _5; + } + + @Override + public _6 _6() { + return _6; + } + + @Override + public _7 _7() { + return _7; + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product8.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product8.java index 46fef4b86..2b51e1bf0 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product8.java @@ -39,4 +39,144 @@ default R into( Fn8 fn) { return Product7.super.>into(fn).apply(_8()); } + + /** + * Rotate all eight values of this product one slot to the left. + * + * @return the left-rotated product + */ + default Product8<_2, _3, _4, _5, _6, _7, _8, _1> rotateL8() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_2, _3, _4, _5, _6, _7, _8, _1)); + } + + /** + * Rotate all eight values of this product one slot to the right. + * + * @return the right-rotated product + */ + default Product8<_8, _1, _2, _3, _4, _5, _6, _7> rotateR8() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_8, _1, _2, _3, _4, _5, _6, _7)); + } + + @Override + default Product8<_2, _3, _4, _5, _6, _7, _1, _8> rotateL7() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_2, _3, _4, _5, _6, _7, _1, _8)); + } + + @Override + default Product8<_7, _1, _2, _3, _4, _5, _6, _8> rotateR7() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_7, _1, _2, _3, _4, _5, _6, _8)); + } + + @Override + default Product8<_2, _3, _4, _5, _6, _1, _7, _8> rotateL6() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_2, _3, _4, _5, _6, _1, _7, _8)); + } + + @Override + default Product8<_6, _1, _2, _3, _4, _5, _7, _8> rotateR6() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_6, _1, _2, _3, _4, _5, _7, _8)); + } + + @Override + default Product8<_2, _3, _4, _5, _1, _6, _7, _8> rotateL5() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_2, _3, _4, _5, _1, _6, _7, _8)); + } + + @Override + default Product8<_5, _1, _2, _3, _4, _6, _7, _8> rotateR5() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_5, _1, _2, _3, _4, _6, _7, _8)); + } + + @Override + default Product8<_2, _3, _4, _1, _5, _6, _7, _8> rotateL4() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_2, _3, _4, _1, _5, _6, _7, _8)); + } + + @Override + default Product8<_4, _1, _2, _3, _5, _6, _7, _8> rotateR4() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_4, _1, _2, _3, _5, _6, _7, _8)); + } + + @Override + default Product8<_2, _3, _1, _4, _5, _6, _7, _8> rotateL3() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_2, _3, _1, _4, _5, _6, _7, _8)); + } + + @Override + default Product8<_3, _1, _2, _4, _5, _6, _7, _8> rotateR3() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_3, _1, _2, _4, _5, _6, _7, _8)); + } + + @Override + default Product8<_2, _1, _3, _4, _5, _6, _7, _8> invert() { + return into((_1, _2, _3, _4, _5, _6, _7, _8) -> product(_2, _1, _3, _4, _5, _6, _7, _8)); + } + + /** + * Static factory method for creating a generic {@link Product8}. + * + * @param _1 the first slot + * @param _2 the second slot + * @param _3 the third slot + * @param _4 the fourth slot + * @param _5 the fifth slot + * @param _6 the sixth slot + * @param _7 the seventh slot + * @param _8 the eighth slot + * @param <_1> the first slot type + * @param <_2> the second slot type + * @param <_3> the third slot type + * @param <_4> the fourth slot type + * @param <_5> the fifth slot type + * @param <_6> the sixth slot type + * @param <_7> the seventh slot type + * @param <_8> the eighth slot type + * @return the {@link Product8} + */ + static <_1, _2, _3, _4, _5, _6, _7, _8> Product8<_1, _2, _3, _4, _5, _6, _7, _8> product(_1 _1, _2 _2, _3 _3, _4 _4, + _5 _5, _6 _6, _7 _7, + _8 _8) { + return new Product8<_1, _2, _3, _4, _5, _6, _7, _8>() { + @Override + public _1 _1() { + return _1; + } + + @Override + public _2 _2() { + return _2; + } + + @Override + public _3 _3() { + return _3; + } + + @Override + public _4 _4() { + return _4; + } + + @Override + public _5 _5() { + return _5; + } + + @Override + public _6 _6() { + return _6; + } + + @Override + public _7 _7() { + return _7; + } + + @Override + public _8 _8() { + return _8; + } + }; + } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/product/Product2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/product/Product2Test.java index d094cd39d..4fe4837e0 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/product/Product2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/product/Product2Test.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.adt.product; +import org.junit.Before; import org.junit.Test; import static com.jnape.palatable.lambda.adt.product.Product2.product; @@ -7,17 +8,21 @@ public class Product2Test { + private Product2 product; + + @Before + public void setUp() { + product = product("a", "b"); + } + @Test public void staticFactoryMethod() { - Product2 product = product("a", "b"); assertEquals("a", product._1()); assertEquals("b", product._2()); } @Test public void invert() { - Product2 inverted = product("a", "b").invert(); - assertEquals("b", inverted._1()); - assertEquals("a", inverted._2()); + assertEquals("ba", product.invert().into((a, b) -> a + b)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/product/Product3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/product/Product3Test.java new file mode 100644 index 000000000..f6533e682 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/adt/product/Product3Test.java @@ -0,0 +1,31 @@ +package com.jnape.palatable.lambda.adt.product; + +import org.junit.Before; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.product.Product3.product; +import static org.junit.Assert.assertEquals; + +public class Product3Test { + + private Product3 product; + + @Before + public void setUp() { + product = product("a", "b", "c"); + } + + @Test + public void staticFactoryMethod() { + assertEquals("a", product._1()); + assertEquals("b", product._2()); + assertEquals("c", product._3()); + } + + @Test + public void rotations() { + assertEquals("bac", product.invert().into((a, b, c) -> a + b + c)); + assertEquals("bca", product.rotateL3().into((a, b, c) -> a + b + c)); + assertEquals("cab", product.rotateR3().into((a, b, c) -> a + b + c)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/product/Product4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/product/Product4Test.java new file mode 100644 index 000000000..12d6b3c19 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/adt/product/Product4Test.java @@ -0,0 +1,34 @@ +package com.jnape.palatable.lambda.adt.product; + +import org.junit.Before; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.product.Product4.product; +import static org.junit.Assert.assertEquals; + +public class Product4Test { + + private Product4 product; + + @Before + public void setUp() { + product = product("a", "b", "c", "d"); + } + + @Test + public void staticFactoryMethod() { + assertEquals("a", product._1()); + assertEquals("b", product._2()); + assertEquals("c", product._3()); + assertEquals("d", product._4()); + } + + @Test + public void rotations() { + assertEquals("bacd", product.invert().into((a, b, c, d) -> a + b + c + d)); + assertEquals("bcad", product.rotateL3().into((a, b, c, d) -> a + b + c + d)); + assertEquals("cabd", product.rotateR3().into((a, b, c, d) -> a + b + c + d)); + assertEquals("bcda", product.rotateL4().into((a, b, c, d) -> a + b + c + d)); + assertEquals("dabc", product.rotateR4().into((a, b, c, d) -> a + b + c + d)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/product/Product5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/product/Product5Test.java new file mode 100644 index 000000000..63723741f --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/adt/product/Product5Test.java @@ -0,0 +1,37 @@ +package com.jnape.palatable.lambda.adt.product; + +import org.junit.Before; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.product.Product5.product; +import static org.junit.Assert.assertEquals; + +public class Product5Test { + + private Product5 product; + + @Before + public void setUp() { + product = product("a", "b", "c", "d", "e"); + } + + @Test + public void staticFactoryMethod() { + assertEquals("a", product._1()); + assertEquals("b", product._2()); + assertEquals("c", product._3()); + assertEquals("d", product._4()); + assertEquals("e", product._5()); + } + + @Test + public void rotations() { + assertEquals("bacde", product.invert().into((a, b, c, d, e) -> a + b + c + d + e)); + assertEquals("bcade", product.rotateL3().into((a, b, c, d, e) -> a + b + c + d + e)); + assertEquals("cabde", product.rotateR3().into((a, b, c, d, e) -> a + b + c + d + e)); + assertEquals("bcdae", product.rotateL4().into((a, b, c, d, e) -> a + b + c + d + e)); + assertEquals("dabce", product.rotateR4().into((a, b, c, d, e) -> a + b + c + d + e)); + assertEquals("bcdea", product.rotateL5().into((a, b, c, d, e) -> a + b + c + d + e)); + assertEquals("eabcd", product.rotateR5().into((a, b, c, d, e) -> a + b + c + d + e)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/product/Product6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/product/Product6Test.java new file mode 100644 index 000000000..aa6e0ceb7 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/adt/product/Product6Test.java @@ -0,0 +1,40 @@ +package com.jnape.palatable.lambda.adt.product; + +import org.junit.Before; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.product.Product6.product; +import static org.junit.Assert.assertEquals; + +public class Product6Test { + + private Product6 product; + + @Before + public void setUp() { + product = product("a", "b", "c", "d", "e", "f"); + } + + @Test + public void staticFactoryMethod() { + assertEquals("a", product._1()); + assertEquals("b", product._2()); + assertEquals("c", product._3()); + assertEquals("d", product._4()); + assertEquals("e", product._5()); + assertEquals("f", product._6()); + } + + @Test + public void rotations() { + assertEquals("bacdef", product.invert().into((a, b, c, d, e, f) -> a + b + c + d + e + f)); + assertEquals("bcadef", product.rotateL3().into((a, b, c, d, e, f) -> a + b + c + d + e + f)); + assertEquals("cabdef", product.rotateR3().into((a, b, c, d, e, f) -> a + b + c + d + e + f)); + assertEquals("bcdaef", product.rotateL4().into((a, b, c, d, e, f) -> a + b + c + d + e + f)); + assertEquals("dabcef", product.rotateR4().into((a, b, c, d, e, f) -> a + b + c + d + e + f)); + assertEquals("bcdeaf", product.rotateL5().into((a, b, c, d, e, f) -> a + b + c + d + e + f)); + assertEquals("eabcdf", product.rotateR5().into((a, b, c, d, e, f) -> a + b + c + d + e + f)); + assertEquals("bcdefa", product.rotateL6().into((a, b, c, d, e, f) -> a + b + c + d + e + f)); + assertEquals("fabcde", product.rotateR6().into((a, b, c, d, e, f) -> a + b + c + d + e + f)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/product/Product7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/product/Product7Test.java new file mode 100644 index 000000000..a5cd04b5f --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/adt/product/Product7Test.java @@ -0,0 +1,43 @@ +package com.jnape.palatable.lambda.adt.product; + +import org.junit.Before; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.product.Product7.product; +import static org.junit.Assert.assertEquals; + +public class Product7Test { + + private Product7 product; + + @Before + public void setUp() { + product = product("a", "b", "c", "d", "e", "f", "g"); + } + + @Test + public void staticFactoryMethod() { + assertEquals("a", product._1()); + assertEquals("b", product._2()); + assertEquals("c", product._3()); + assertEquals("d", product._4()); + assertEquals("e", product._5()); + assertEquals("f", product._6()); + assertEquals("g", product._7()); + } + + @Test + public void rotations() { + assertEquals("bacdefg", product.invert().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("bcadefg", product.rotateL3().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("cabdefg", product.rotateR3().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("bcdaefg", product.rotateL4().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("dabcefg", product.rotateR4().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("bcdeafg", product.rotateL5().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("eabcdfg", product.rotateR5().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("bcdefag", product.rotateL6().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("fabcdeg", product.rotateR6().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("bcdefga", product.rotateL7().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + assertEquals("gabcdef", product.rotateR7().into((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/product/Product8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/product/Product8Test.java new file mode 100644 index 000000000..64360b763 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/adt/product/Product8Test.java @@ -0,0 +1,46 @@ +package com.jnape.palatable.lambda.adt.product; + +import org.junit.Before; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.product.Product8.product; +import static org.junit.Assert.assertEquals; + +public class Product8Test { + + private Product8 product; + + @Before + public void setUp() { + product = product("a", "b", "c", "d", "e", "f", "g", "h"); + } + + @Test + public void staticFactoryMethod() { + assertEquals("a", product._1()); + assertEquals("b", product._2()); + assertEquals("c", product._3()); + assertEquals("d", product._4()); + assertEquals("e", product._5()); + assertEquals("f", product._6()); + assertEquals("g", product._7()); + assertEquals("h", product._8()); + } + + @Test + public void rotations() { + assertEquals("bacdefgh", product.invert().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("bcadefgh", product.rotateL3().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("cabdefgh", product.rotateR3().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("bcdaefgh", product.rotateL4().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("dabcefgh", product.rotateR4().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("bcdeafgh", product.rotateL5().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("eabcdfgh", product.rotateR5().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("bcdefagh", product.rotateL6().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("fabcdegh", product.rotateR6().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("bcdefgah", product.rotateL7().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("gabcdefh", product.rotateR7().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("bcdefgha", product.rotateL8().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + assertEquals("habcdefg", product.rotateR8().into((a, b, c, d, e, f, g, h) -> a + b + c + d + e + f + g + h)); + } +} \ No newline at end of file From d64c078a21d07a13b196b93469758a70d2f9b724 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 5 Aug 2018 17:37:07 -0500 Subject: [PATCH 069/348] Effect#apply() now the required method to implement --- CHANGELOG.md | 1 + .../palatable/lambda/functions/Effect.java | 33 +++++++++++++++---- .../lambda/functions/specialized/Noop.java | 6 +--- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baf77d010..7670e2229 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to `functions.builtin.fn2` package - ***Breaking Change***: `Absent` moved to `semigroup.builtin` package - `RightAny` overload returns `Monoid` +- `Effect#apply()` is now the required method to implement in the functional interface ### Added - `Predicate#predicate` static factory method diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 62bfb941e..ead5d645f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -20,8 +20,9 @@ public interface Effect extends Fn1, Consumer { @Override - default void accept(A a) { - apply(a); + default Unit apply(A a) { + accept(a); + return UNIT; } @Override @@ -46,9 +47,27 @@ default Effect discardR(Applicative> appB) { @Override default Effect andThen(Consumer after) { - return a -> { - Consumer.super.andThen(after).accept(a); - return UNIT; - }; + return Consumer.super.andThen(after)::accept; } -} + + /** + * Static factory method to aid in inference. + * + * @param effect the effect + * @param the effect argument type + * @return the effect + */ + static Effect effect(Consumer effect) { + return effect::accept; + } + + /** + * Create an {@link Effect} from a {@link Runnable}; + * + * @param runnable the runnable + * @return the effect + */ + static Effect effect(Runnable runnable) { + return effect(__ -> runnable.run()); + } +} \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java index 2977f5f58..62c5192f4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java @@ -1,10 +1,7 @@ package com.jnape.palatable.lambda.functions.specialized; -import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functions.Effect; -import static com.jnape.palatable.lambda.adt.Unit.UNIT; - /** * As the name might suggest, this is an {@link Effect} that, *ahem*, has no effect. * @@ -17,8 +14,7 @@ private Noop() { } @Override - public Unit apply(A a) { - return UNIT; + public void accept(A a) { } /** From 32e084b20dce602c28d21506c66d9dd09521f0fb Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 5 Aug 2018 17:47:15 -0500 Subject: [PATCH 070/348] Fn0#apply() is now the method to implement --- CHANGELOG.md | 3 +- .../jnape/palatable/lambda/functions/Fn0.java | 39 ++++++++----------- .../jnape/palatable/lambda/functions/Fn1.java | 2 +- .../palatable/lambda/functions/Fn0Test.java | 3 +- .../java/testsupport/EqualityAwareFn0.java | 7 +++- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7670e2229..82cf09770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to `functions.builtin.fn2` package - ***Breaking Change***: `Absent` moved to `semigroup.builtin` package +- ***Breaking Change***: `Effect#accept()` is now the required method to implement in the functional interface +- ***Breaking Change***: `Fn0#apply()` is now the required method to implement in the functional interface - `RightAny` overload returns `Monoid` -- `Effect#apply()` is now the required method to implement in the functional interface ### Added - `Predicate#predicate` static factory method diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index c3599b84f..357a28a3c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -8,6 +8,7 @@ import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.Effect.effect; /** * A function taking "no arguments", implemented as an {@link Fn1}<{@link Unit}, A>. @@ -19,6 +20,8 @@ @FunctionalInterface public interface Fn0 extends Fn1, Supplier { + A apply(); + /** * Invoke this function with {@link Unit}. * @@ -26,55 +29,48 @@ public interface Fn0 extends Fn1, Supplier { * @return the result value */ @Override - A apply(Unit unit); - - /** - * Apply this {@link Fn0}, supplying {@link Unit} as the input. - * - * @return the output - */ - default A apply() { - return apply(UNIT); + default A apply(Unit unit) { + return apply(); } @Override default Fn0 flatMap(Function>> f) { - return Fn1.super.flatMap(f)::apply; + return Fn1.super.flatMap(f).thunk(UNIT); } @Override default Fn0 fmap(Function f) { - return Fn1.super.fmap(f)::apply; + return Fn1.super.fmap(f).thunk(UNIT); } @Override default Fn0 pure(B b) { - return Fn1.super.pure(b)::apply; + return Fn1.super.pure(b).thunk(UNIT); } @Override default Fn0 zip(Applicative, Fn1> appFn) { - return Fn1.super.zip(appFn)::apply; + return Fn1.super.zip(appFn).thunk(UNIT); } @Override default Fn0 zip(Fn2 appFn) { - return Fn1.super.zip(appFn)::apply; + return Fn1.super.zip(appFn).thunk(UNIT); } @Override default Fn0 discardL(Applicative> appB) { - return Fn1.super.discardL(appB)::apply; + return Fn1.super.discardL(appB).thunk(UNIT); } @Override default Fn0 discardR(Applicative> appB) { - return Fn1.super.discardR(appB)::apply; + return Fn1.super.discardR(appB).thunk(UNIT); } @Override default Fn0 diMapR(Function fn) { - return Fn1.super.diMapR(fn)::apply; + return Fn1.super.diMapR(fn).thunk(UNIT); } @Override @@ -84,7 +80,7 @@ default Fn1 compose(Function before) { @Override default Fn0 andThen(Function after) { - return Fn1.super.andThen(after)::apply; + return Fn1.super.andThen(after).thunk(UNIT); } @Override @@ -100,7 +96,7 @@ default A get() { * @return the {@link Fn0} */ static Fn0 fn0(Supplier supplier) { - return __ -> supplier.get(); + return supplier::get; } /** @@ -121,10 +117,7 @@ static Fn0 fn0(Fn0 fn) { * @return the {@link Fn0} */ static Fn0 fn0(Runnable fn) { - return unit -> { - fn.run(); - return unit; - }; + return effect(fn).thunk(UNIT); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 2d52031ce..092b5b953 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -36,7 +36,7 @@ public interface Fn1 extends Monad>, Profunctor, F * @return an {@link Fn0} */ default Fn0 thunk(A a) { - return __ -> apply(a); + return () -> apply(a); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java index d57027c70..d04084205 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java @@ -8,6 +8,7 @@ import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @RunWith(Traits.class) @@ -15,6 +16,6 @@ public class Fn0Test { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) public Fn0 testSubject() { - return new EqualityAwareFn0<>(constantly(1)::apply); + return new EqualityAwareFn0<>(constantly(1).thunk(UNIT)); } } \ No newline at end of file diff --git a/src/test/java/testsupport/EqualityAwareFn0.java b/src/test/java/testsupport/EqualityAwareFn0.java index 188c5b49b..17b3318d5 100644 --- a/src/test/java/testsupport/EqualityAwareFn0.java +++ b/src/test/java/testsupport/EqualityAwareFn0.java @@ -18,9 +18,14 @@ public EqualityAwareFn0(Fn0 fn) { this.fn = fn; } + @Override + public A apply() { + return fn.apply(); + } + @Override public A apply(Unit unit) { - return fn.apply(unit); + return apply(); } @Override From dfa22e5ee803013a3fd637c11122a6ce4bf3c6bf Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 17 Aug 2018 17:58:27 -0500 Subject: [PATCH 071/348] Adding CheckedEffect1 and CheckedFn1 static factory method --- CHANGELOG.md | 4 +- .../specialized/checked/CheckedEffect1.java | 48 +++++++++++++++++++ .../specialized/checked/CheckedFn1.java | 14 ++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect1.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 82cf09770..0f25b3ac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `Predicate#predicate` static factory method - `Product2-8` left/right rotation methods -- `Tuple2-8` specializations of left/right product rotation +- `Tuple2-8` specializations of left/right product rotation +- `CheckedEffect`, an `Effect` variant that can throw checked exceptions +- `CheckedFn1#checked`, convenience static factory method to aid inference ## [3.1.0] - 2018-07-16 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect1.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect1.java new file mode 100644 index 000000000..aa459b4da --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect1.java @@ -0,0 +1,48 @@ +package com.jnape.palatable.lambda.functions.specialized.checked; + +import com.jnape.palatable.lambda.functions.Effect; + +import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; + +/** + * Specialized {@link Effect} that can throw any {@link Throwable}. + * + * @param The {@link Throwable} type + * @param The input type + * @see CheckedRunnable + * @see CheckedFn1 + * @see Effect + */ +@FunctionalInterface +public interface CheckedEffect1 extends Effect { + + @Override + default void accept(A a) { + try { + checkedAccept(a); + } catch (Throwable t) { + throw throwChecked(t); + } + } + + /** + * A version of {@link Effect#accept} that can throw checked exceptions. + * + * @param a the effect argument + * @throws T any exception that can be thrown by this method + */ + void checkedAccept(A a) throws T; + + /** + * Convenience static factory method for constructing a {@link CheckedEffect1} without an explicit cast or type + * attribution at the call site. + * + * @param checkedEffect the checked effect + * @param the inferred Throwable type + * @param the input type + * @return the checked effect + */ + static CheckedEffect1 checked(CheckedEffect1 checkedEffect) { + return checkedEffect; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java index 3d5a9176c..e35dd70da 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java @@ -34,4 +34,18 @@ default B apply(A a) { * @throws T any exception that can be thrown by this method */ B checkedApply(A a) throws T; + + /** + * Convenience static factory method for constructing a {@link CheckedFn1} without an explicit cast or type + * attribution at the call site. + * + * @param checkedFn1 the checked fn1 + * @param the inferred Throwable type + * @param the input type + * @param the output type + * @return the checked fn1 + */ + static CheckedFn1 checked(CheckedFn1 checkedFn1) { + return checkedFn1; + } } From 6c608b415c7249d0937a2ec4203a63a4be620f17 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 Aug 2018 16:59:21 -0500 Subject: [PATCH 072/348] Reworking monoid folds to rely on foldmap monoid folding now implicitly starts with identity AddAll monoid no longer mutates argument references AddAll semigroup deprecated in favor of monoid --- CHANGELOG.md | 7 +++++ .../jnape/palatable/lambda/adt/Either.java | 5 +-- .../com/jnape/palatable/lambda/adt/Try.java | 2 +- .../lambda/functions/builtin/fn1/Not.java | 8 ++--- .../lambda/functions/builtin/fn2/All.java | 8 ++--- .../lambda/functions/builtin/fn2/Any.java | 8 ++--- .../functions/builtin/fn2/DropWhile.java | 8 ++--- .../lambda/functions/builtin/fn2/Filter.java | 8 ++--- .../lambda/functions/builtin/fn2/Find.java | 8 ++--- .../functions/builtin/fn2/MagnetizeBy.java | 8 ++--- .../lambda/functions/builtin/fn2/Span.java | 9 +++--- .../functions/builtin/fn2/TakeWhile.java | 8 ++--- .../functions/builtin/fn4/IfThenElse.java | 12 +++---- .../functions/specialized/Predicate.java | 2 +- .../lambda/iteration/FilteringIterable.java | 10 +++--- .../lambda/iteration/FilteringIterator.java | 6 ++-- .../iteration/PredicatedDroppingIterable.java | 10 +++--- .../iteration/PredicatedDroppingIterator.java | 8 ++--- .../iteration/PredicatedTakingIterable.java | 10 +++--- .../iteration/PredicatedTakingIterator.java | 8 ++--- .../jnape/palatable/lambda/monoid/Monoid.java | 14 +++++---- .../lambda/monoid/builtin/AddAll.java | 31 ++++++++++++++++--- .../palatable/lambda/monoid/builtin/And.java | 8 +++-- .../lambda/monoid/builtin/Concat.java | 9 ++++++ .../lambda/monoid/builtin/First.java | 7 +++-- .../palatable/lambda/monoid/builtin/Or.java | 8 +++-- .../lambda/semigroup/builtin/AddAll.java | 2 ++ .../lambda/functions/builtin/fn2/AllTest.java | 4 +-- .../lambda/functions/builtin/fn2/AnyTest.java | 2 +- .../lambda/semigroup/builtin/AddAllTest.java | 20 ------------ 30 files changed, 144 insertions(+), 114 deletions(-) delete mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AddAllTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f25b3ac8..889c223eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - ***Breaking Change***: `Effect#accept()` is now the required method to implement in the functional interface - ***Breaking Change***: `Fn0#apply()` is now the required method to implement in the functional interface - `RightAny` overload returns `Monoid` +- monoids now all fold with respect to `foldMap` +- monoid folding now implicitly starts with the identity, regardless of iterable population +- `Concat` monoid can now fold infinite iterables +- all `Function` are now `Function` for better compatibility ### Added - `Predicate#predicate` static factory method @@ -18,6 +22,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `CheckedEffect`, an `Effect` variant that can throw checked exceptions - `CheckedFn1#checked`, convenience static factory method to aid inference +### Deprecated +- `AddAll` semigroup, in favor of the monoid that no longer mutates any argument + ## [3.1.0] - 2018-07-16 ### Added - `Fn3-8` static factory overloads to aid in coercing lambdas 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 be6ed52ac..d9c9d2fa1 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -92,7 +92,7 @@ public final R orThrow(Function th * @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(Function pred, Supplier leftSupplier) { + public final Either filter(Function pred, Supplier leftSupplier) { return filter(pred, __ -> leftSupplier.get()); } @@ -105,7 +105,8 @@ public final Either filter(Function pred, Supplier * @return this is a left value or a right value that pred matches; otherwise, the result of leftFn applied to the * right value, wrapped in a left */ - public final Either filter(Function pred, Function leftFn) { + public final Either filter(Function pred, + Function leftFn) { return flatMap(r -> pred.apply(r) ? right(r) : left(leftFn.apply(r))); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index 74dded5cb..d629a967b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -52,7 +52,7 @@ public final Try catching(Class throwableType, Function catching(Function predicate, + public final Try catching(Function predicate, Function recoveryFn) { return match(t -> predicate.apply(t) ? success(recoveryFn.apply(t)) : failure(t), Try::success); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java index 5f8718c8b..5f0bb8691 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java @@ -10,14 +10,14 @@ * * @param the input argument type */ -public final class Not implements BiPredicate, A> { +public final class Not implements BiPredicate, A> { private static final Not INSTANCE = new Not(); private Not() { } @Override - public Boolean apply(Function pred, A a) { + public Boolean apply(Function pred, A a) { return !pred.apply(a); } @@ -26,11 +26,11 @@ public static Not not() { return INSTANCE; } - public static Predicate not(Function pred) { + public static Predicate not(Function pred) { return Not.not().apply(pred); } - public static Boolean not(Function pred, A a) { + public static Boolean not(Function pred, A a) { return not(pred).apply(a); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java index 53ecac095..2aeb00eca 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java @@ -13,7 +13,7 @@ * @param The input Iterable element type * @see Any */ -public final class All implements BiPredicate, Iterable> { +public final class All implements BiPredicate, Iterable> { private static final All INSTANCE = new All(); @@ -21,7 +21,7 @@ private All() { } @Override - public Boolean apply(Function predicate, Iterable as) { + public Boolean apply(Function predicate, Iterable as) { for (A a : as) if (!predicate.apply(a)) return false; @@ -34,11 +34,11 @@ public static All all() { return INSTANCE; } - public static Fn1, Boolean> all(Function predicate) { + public static Fn1, ? extends Boolean> all(Function predicate) { return All.all().apply(predicate); } - public static Boolean all(Function predicate, Iterable as) { + public static Boolean all(Function predicate, Iterable as) { return All.all(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java index fa8db83b4..6285084f5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java @@ -13,7 +13,7 @@ * @param The input Iterable element type * @see All */ -public final class Any implements BiPredicate, Iterable> { +public final class Any implements BiPredicate, Iterable> { private static final Any INSTANCE = new Any(); @@ -21,7 +21,7 @@ private Any() { } @Override - public Boolean apply(Function predicate, Iterable as) { + public Boolean apply(Function predicate, Iterable as) { for (A a : as) if (predicate.apply(a)) return true; @@ -34,11 +34,11 @@ public static Any any() { return INSTANCE; } - public static Predicate> any(Function predicate) { + public static Predicate> any(Function predicate) { return Any.any().apply(predicate); } - public static Boolean any(Function predicate, Iterable as) { + public static Boolean any(Function predicate, Iterable as) { return Any.any(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java index 9b87e63b0..560f35c5c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java @@ -16,7 +16,7 @@ * @see TakeWhile */ -public final class DropWhile implements Fn2, Iterable, Iterable> { +public final class DropWhile implements Fn2, Iterable, Iterable> { private static final DropWhile INSTANCE = new DropWhile(); @@ -24,7 +24,7 @@ private DropWhile() { } @Override - public Iterable apply(Function predicate, Iterable as) { + public Iterable apply(Function predicate, Iterable as) { return new PredicatedDroppingIterable<>(predicate, as); } @@ -33,11 +33,11 @@ public static DropWhile dropWhile() { return INSTANCE; } - public static Fn1, Iterable> dropWhile(Function predicate) { + public static Fn1, Iterable> dropWhile(Function predicate) { return DropWhile.dropWhile().apply(predicate); } - public static Iterable dropWhile(Function predicate, Iterable as) { + public static Iterable dropWhile(Function predicate, Iterable as) { return DropWhile.dropWhile(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java index 787978318..fd0c70e7a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java @@ -14,7 +14,7 @@ * @see TakeWhile * @see DropWhile */ -public final class Filter implements Fn2, Iterable, Iterable> { +public final class Filter implements Fn2, Iterable, Iterable> { private static final Filter INSTANCE = new Filter(); @@ -22,7 +22,7 @@ private Filter() { } @Override - public Iterable apply(Function predicate, Iterable as) { + public Iterable apply(Function predicate, Iterable as) { return new FilteringIterable<>(predicate, as); } @@ -31,11 +31,11 @@ public static Filter filter() { return INSTANCE; } - public static Fn1, Iterable> filter(Function predicate) { + public static Fn1, Iterable> filter(Function predicate) { return Filter.filter().apply(predicate); } - public static Iterable filter(Function predicate, Iterable as) { + public static Iterable filter(Function predicate, Iterable as) { return Filter.filter(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java index e1bb57be7..716a4f3e8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java @@ -18,7 +18,7 @@ * * @param the Iterable element type */ -public final class Find implements Fn2, Iterable, Maybe> { +public final class Find implements Fn2, Iterable, Maybe> { private static final Find INSTANCE = new Find(); @@ -26,7 +26,7 @@ private Find() { } @Override - public Maybe apply(Function predicate, Iterable as) { + public Maybe apply(Function predicate, Iterable as) { return head(dropWhile(not(predicate), as)); } @@ -35,11 +35,11 @@ public static Find find() { return INSTANCE; } - public static Fn1, Maybe> find(Function predicate) { + public static Fn1, Maybe> find(Function predicate) { return Find.find().apply(predicate); } - public static Maybe find(Function predicate, Iterable as) { + public static Maybe find(Function predicate, Iterable as) { return Find.find(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java index a7e512cc7..ef94c372a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java @@ -25,7 +25,7 @@ * * @param the {@link Iterable} element type */ -public final class MagnetizeBy implements Fn2, Iterable, Iterable>> { +public final class MagnetizeBy implements Fn2, Iterable, Iterable>> { private static final MagnetizeBy INSTANCE = new MagnetizeBy(); @@ -33,7 +33,7 @@ private MagnetizeBy() { } @Override - public Iterable> apply(BiFunction predicate, Iterable as) { + public Iterable> apply(BiFunction predicate, Iterable as) { return () -> uncons(as).fmap(into((A head, Iterable tail) -> { Iterable group = cons(head, unfoldr(into((pivot, ys) -> uncons(ys) .flatMap(into((y, recurse) -> predicate.apply(pivot, y) @@ -49,12 +49,12 @@ public static MagnetizeBy magnetizeBy() { } public static Fn1, Iterable>> magnetizeBy( - BiFunction predicate) { + BiFunction predicate) { return MagnetizeBy.magnetizeBy().apply(predicate); } public static Iterable> magnetizeBy( - BiFunction predicate, + BiFunction predicate, Iterable as) { return MagnetizeBy.magnetizeBy(predicate).apply(as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java index cd41bc74a..aea792d08 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java @@ -15,7 +15,7 @@ * * @param the {@link Iterable} element type */ -public final class Span implements Fn2, Iterable, Tuple2, Iterable>> { +public final class Span implements Fn2, Iterable, Tuple2, Iterable>> { private static final Span INSTANCE = new Span(); @@ -23,7 +23,7 @@ private Span() { } @Override - public Tuple2, Iterable> apply(Function predicate, Iterable as) { + public Tuple2, Iterable> apply(Function predicate, Iterable as) { return Tuple2.fill(as).biMap(takeWhile(predicate), dropWhile(predicate)); } @@ -32,11 +32,12 @@ public static Span span() { return INSTANCE; } - public static Fn1, Tuple2, Iterable>> span(Function predicate) { + public static Fn1, Tuple2, Iterable>> span( + Function predicate) { return Span.span().apply(predicate); } - public static Tuple2, Iterable> span(Function predicate, + public static Tuple2, Iterable> span(Function predicate, Iterable as) { return Span.span(predicate).apply(as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java index 0b7bc7621..8285d953c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java @@ -15,7 +15,7 @@ * @see Filter * @see DropWhile */ -public final class TakeWhile implements Fn2, Iterable, Iterable> { +public final class TakeWhile implements Fn2, Iterable, Iterable> { private static final TakeWhile INSTANCE = new TakeWhile(); @@ -23,7 +23,7 @@ private TakeWhile() { } @Override - public Iterable apply(Function predicate, Iterable as) { + public Iterable apply(Function predicate, Iterable as) { return new PredicatedTakingIterable<>(predicate, as); } @@ -32,11 +32,11 @@ public static TakeWhile takeWhile() { return INSTANCE; } - public static Fn1, Iterable> takeWhile(Function predicate) { + public static Fn1, Iterable> takeWhile(Function predicate) { return TakeWhile.takeWhile().apply(predicate); } - public static Iterable takeWhile(Function predicate, Iterable as) { + public static Iterable takeWhile(Function predicate, Iterable as) { return TakeWhile.takeWhile(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java index fe353a497..d67440595 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java @@ -7,7 +7,7 @@ import java.util.function.Function; -public final class IfThenElse implements Fn4, Function, Function, A, B> { +public final class IfThenElse implements Fn4, Function, Function, A, B> { private static final IfThenElse INSTANCE = new IfThenElse(); @@ -15,7 +15,7 @@ private IfThenElse() { } @Override - public B apply(Function predicate, Function thenCase, + public B apply(Function predicate, Function thenCase, Function elseCase, A a) { return predicate.apply(a) ? thenCase.apply(a) : elseCase.apply(a); } @@ -26,23 +26,23 @@ public static IfThenElse ifThenElse() { } public static Fn3, Function, A, B> ifThenElse( - Function predicate) { + Function predicate) { return IfThenElse.ifThenElse().apply(predicate); } public static Fn2, A, B> ifThenElse( - Function predicate, Function thenCase) { + Function predicate, Function thenCase) { return IfThenElse.ifThenElse(predicate).apply(thenCase); } public static Fn1 ifThenElse( - Function predicate, Function thenCase, + Function predicate, Function thenCase, Function elseCase) { return IfThenElse.ifThenElse(predicate, thenCase).apply(elseCase); } public static B ifThenElse( - Function predicate, Function thenCase, + Function predicate, Function thenCase, Function elseCase, A a) { return ifThenElse(predicate, thenCase, elseCase).apply(a); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java index a9d0de708..2138db821 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java @@ -90,7 +90,7 @@ default Predicate negate() { * @param the input type * @return the predicate */ - static Predicate predicate(Function predicate) { + static Predicate predicate(Function predicate) { return predicate::apply; } } 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 4d3096051..1b9f315ff 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java @@ -9,11 +9,11 @@ import static java.util.Collections.singletonList; public final class FilteringIterable implements Iterable { - private final List> predicates; - private final Iterable as; + private final List> predicates; + private final Iterable as; - public FilteringIterable(Function predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + public FilteringIterable(Function predicate, Iterable as) { + List> predicates = new ArrayList<>(singletonList(predicate)); while (as instanceof FilteringIterable) { FilteringIterable nested = (FilteringIterable) as; predicates.addAll(0, nested.predicates); @@ -25,7 +25,7 @@ public FilteringIterable(Function predicate, Iterable as) @Override public Iterator iterator() { - Function metaPredicate = a -> all(p -> p.apply(a), predicates); + Function metaPredicate = a -> all(p -> p.apply(a), predicates); return new FilteringIterator<>(metaPredicate, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java index cde34d842..5b9358c01 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java @@ -6,10 +6,10 @@ public final class FilteringIterator extends ImmutableIterator { - private final Function predicate; - private final RewindableIterator rewindableIterator; + private final Function predicate; + private final RewindableIterator rewindableIterator; - public FilteringIterator(Function predicate, Iterator iterator) { + public FilteringIterator(Function predicate, Iterator iterator) { this.predicate = predicate; rewindableIterator = new RewindableIterator<>(iterator); } 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 10338ca7c..bd3aa87b6 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java @@ -9,11 +9,11 @@ import static java.util.Collections.singletonList; public final class PredicatedDroppingIterable implements Iterable { - private final List> predicates; - private final Iterable as; + private final List> predicates; + private final Iterable as; - public PredicatedDroppingIterable(Function predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + public PredicatedDroppingIterable(Function predicate, Iterable as) { + List> predicates = new ArrayList<>(singletonList(predicate)); while (as instanceof PredicatedDroppingIterable) { PredicatedDroppingIterable nested = (PredicatedDroppingIterable) as; @@ -26,7 +26,7 @@ public PredicatedDroppingIterable(Function predicate, Iterab @Override public Iterator iterator() { - Function metaPredicate = a -> any(p -> p.apply(a), predicates); + Function metaPredicate = a -> any(p -> p.apply(a), predicates); return new PredicatedDroppingIterator<>(metaPredicate, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java index 852ee37ed..7fe16c64b 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java @@ -5,11 +5,11 @@ import java.util.function.Function; public final class PredicatedDroppingIterator extends ImmutableIterator { - private final Function predicate; - private final RewindableIterator rewindableIterator; - private boolean finishedDropping; + private final Function predicate; + private final RewindableIterator rewindableIterator; + private boolean finishedDropping; - public PredicatedDroppingIterator(Function predicate, Iterator asIterator) { + public PredicatedDroppingIterator(Function predicate, Iterator asIterator) { this.predicate = predicate; rewindableIterator = new RewindableIterator<>(asIterator); finishedDropping = false; 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 dc15675a7..14201849d 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java @@ -9,11 +9,11 @@ import static java.util.Collections.singletonList; public final class PredicatedTakingIterable implements Iterable { - private final List> predicates; - private final Iterable as; + private final List> predicates; + private final Iterable as; - public PredicatedTakingIterable(Function predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + public PredicatedTakingIterable(Function predicate, Iterable as) { + List> predicates = new ArrayList<>(singletonList(predicate)); while (as instanceof PredicatedTakingIterable) { PredicatedTakingIterable nested = (PredicatedTakingIterable) as; predicates.addAll(0, nested.predicates); @@ -25,7 +25,7 @@ public PredicatedTakingIterable(Function predicate, Iterable @Override public Iterator iterator() { - Function metaPredicate = a -> all(p -> p.apply(a), predicates); + Function metaPredicate = a -> all(p -> p.apply(a), predicates); return new PredicatedTakingIterator<>(metaPredicate, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java index 6612b50d1..370ef1e84 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java @@ -5,11 +5,11 @@ import java.util.function.Function; public final class PredicatedTakingIterator extends ImmutableIterator { - private final Function predicate; - private final RewindableIterator rewindableIterator; - private boolean stillTaking; + private final Function predicate; + private final RewindableIterator rewindableIterator; + private boolean stillTaking; - public PredicatedTakingIterator(Function predicate, + public PredicatedTakingIterator(Function predicate, Iterator asIterator) { this.predicate = predicate; rewindableIterator = new RewindableIterator<>(asIterator); diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java index 1a18a2f8a..6cdf12b1e 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java @@ -3,14 +3,16 @@ import com.jnape.palatable.lambda.functions.builtin.fn2.Map; import com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft; import com.jnape.palatable.lambda.functions.builtin.fn2.ReduceRight; +import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; import com.jnape.palatable.lambda.semigroup.Semigroup; import java.util.function.Function; import java.util.function.Supplier; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Reverse.reverse; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Snoc.snoc; /** * A {@link Monoid} is the pairing of a {@link Semigroup} with an identity element. @@ -35,7 +37,7 @@ public interface Monoid extends Semigroup { * @see ReduceLeft */ default A reduceLeft(Iterable as) { - return ReduceLeft.reduceLeft(toBiFunction(), as).orElse(identity()); + return foldMap(id(), as); } /** @@ -47,7 +49,7 @@ default A reduceLeft(Iterable as) { * @see ReduceRight */ default A reduceRight(Iterable as) { - return ReduceRight.reduceRight(toBiFunction(), as).orElse(identity()); + return flip().foldMap(id(), reverse(as)); } /** @@ -63,7 +65,7 @@ default A reduceRight(Iterable as) { * @see Monoid#reduceLeft(Iterable) */ default A foldMap(Function fn, Iterable bs) { - return reduceLeft(map(fn, bs)); + return FoldLeft.foldLeft(this.toBiFunction(), identity(), map(fn, bs)); } /** @@ -71,7 +73,7 @@ default A foldMap(Function fn, Iterable bs) { */ @Override default A foldLeft(A a, Iterable as) { - return reduceLeft(cons(a, as)); + return foldMap(id(), cons(a, as)); } /** @@ -79,7 +81,7 @@ default A foldLeft(A a, Iterable as) { */ @Override default A foldRight(A a, Iterable as) { - return reduceRight(snoc(a, as)); + return flip().foldMap(id(), reverse(cons(a, as))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java index fa0d0221d..6cce48bfd 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java @@ -1,20 +1,21 @@ package com.jnape.palatable.lambda.monoid.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; import com.jnape.palatable.lambda.monoid.Monoid; -import com.jnape.palatable.lambda.semigroup.Semigroup; import java.util.Collection; +import java.util.function.Function; import java.util.function.Supplier; -import static com.jnape.palatable.lambda.monoid.Monoid.monoid; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; /** * The {@link Monoid} instance formed under mutative concatenation for an arbitrary {@link Collection}. The collection * subtype (C) must support {@link Collection#addAll(Collection)}. *

- * For the {@link Semigroup}, see {@link com.jnape.palatable.lambda.semigroup.builtin.AddAll}. + * Note that the result is a new collection, and the inputs to this monoid are left unmodified. * * @see Monoid */ @@ -27,8 +28,28 @@ private AddAll() { @Override public Monoid apply(Supplier cSupplier) { - Semigroup semigroup = com.jnape.palatable.lambda.semigroup.builtin.AddAll.addAll(); - return monoid(semigroup, cSupplier); + return new Monoid() { + @Override + public C identity() { + return cSupplier.get(); + } + + @Override + public C apply(C xs, C ys) { + C c = identity(); + c.addAll(xs); + c.addAll(ys); + return c; + } + + @Override + public C foldMap(Function fn, Iterable bs) { + return FoldLeft.foldLeft((x, y) -> { + x.addAll(y); + return x; + }, identity(), map(fn, bs)); + } + }; } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java index 9b4baec9b..3465ca0f8 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java @@ -4,7 +4,9 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.monoid.Monoid; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Not.not; import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find; @@ -32,8 +34,8 @@ public Boolean apply(Boolean x, Boolean y) { } @Override - public Boolean reduceLeft(Iterable bools) { - return find(not(id()), bools).orElse(true); + public Boolean foldMap(Function fn, Iterable bs) { + return find(not(fn), bs).fmap(constantly(false)).orElse(true); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java index ec38b568b..2d164bbdc 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java @@ -5,6 +5,10 @@ import com.jnape.palatable.lambda.monoid.Monoid; import java.util.Collections; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; /** * The {@link Monoid} instance formed under concatenation for an arbitrary {@link Iterable}. @@ -28,6 +32,11 @@ public Iterable apply(Iterable xs, Iterable ys) { return new ConcatenatingIterable<>(xs, ys); } + @Override + public Iterable foldMap(Function> fn, Iterable bs) { + return flatten(map(fn, bs)); + } + @SuppressWarnings("unchecked") public static Concat concat() { return INSTANCE; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java index 97028b692..cb3b65f4c 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java @@ -4,9 +4,12 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.monoid.Monoid; +import java.util.function.Function; + import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.CatMaybes.catMaybes; import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; /** * A {@link Monoid} instance formed by {@link Maybe}<A>. The application to two {@link Maybe} values @@ -36,8 +39,8 @@ public Maybe apply(Maybe x, Maybe y) { } @Override - public Maybe reduceLeft(Iterable> maybes) { - return head(catMaybes(maybes)); + public Maybe foldMap(Function> fn, Iterable bs) { + return head(catMaybes(map(fn, bs))); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java index 951e555e6..a8157d0fb 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java @@ -4,7 +4,9 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.monoid.Monoid; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find; /** @@ -36,8 +38,8 @@ public boolean test(Boolean x, Boolean y) { } @Override - public Boolean reduceLeft(Iterable bools) { - return find(id(), bools).orElse(false); + public Boolean foldMap(Function fn, Iterable bs) { + return find(fn::apply, bs).fmap(constantly(true)).orElse(false); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/AddAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/AddAll.java index 557f9454b..fe22ba5c2 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/AddAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/AddAll.java @@ -13,7 +13,9 @@ * For the {@link Monoid}, see {@link com.jnape.palatable.lambda.monoid.builtin.AddAll}. * * @see Semigroup + * @deprecated in favor of the now non-modifying {@link com.jnape.palatable.lambda.monoid.builtin.AddAll monoid} */ +@Deprecated public final class AddAll> implements Semigroup { private static final AddAll INSTANCE = new AddAll(); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java index d746b0fc1..c266a4bfb 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java @@ -19,10 +19,10 @@ @RunWith(Traits.class) public class AllTest { - private static final Function EVEN = x -> x.doubleValue() % 2 == 0; + private static final Function EVEN = x -> x.doubleValue() % 2 == 0; @TestTraits({EmptyIterableSupport.class}) - public Fn1, Boolean> createTestSubject() { + public Fn1, ? extends Boolean> createTestSubject() { return all(constantly(true)); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java index aa8f8a118..ff632730b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java @@ -19,7 +19,7 @@ @RunWith(Traits.class) public class AnyTest { - public static final Function EVEN = x -> x % 2 == 0; + public static final Function EVEN = x -> x % 2 == 0; @TestTraits({EmptyIterableSupport.class}) public Fn1, Boolean> createTestSubject() { diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AddAllTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AddAllTest.java deleted file mode 100644 index f1840b5de..000000000 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AddAllTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.jnape.palatable.lambda.semigroup.builtin; - -import org.junit.Test; - -import java.util.HashSet; - -import static com.jnape.palatable.lambda.semigroup.builtin.AddAll.addAll; -import static java.util.Collections.singleton; -import static org.junit.Assert.assertEquals; - -public class AddAllTest { - - @Test - public void semigroup() { - assertEquals(new HashSet() {{ - add(1); - add(2); - }}, addAll(new HashSet<>(singleton(1)), new HashSet<>(singleton(2)))); - } -} \ No newline at end of file From 7b48751936f9f68c6bb6825c173cfe1b98401d86 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 Aug 2018 17:28:31 -0500 Subject: [PATCH 073/348] Renaming CheckedEffect1 to CheckedEffect --- .../checked/{CheckedEffect1.java => CheckedEffect.java} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/{CheckedEffect1.java => CheckedEffect.java} (83%) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect1.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java similarity index 83% rename from src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect1.java rename to src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java index aa459b4da..0197295ee 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java @@ -14,7 +14,7 @@ * @see Effect */ @FunctionalInterface -public interface CheckedEffect1 extends Effect { +public interface CheckedEffect extends Effect { @Override default void accept(A a) { @@ -34,7 +34,7 @@ default void accept(A a) { void checkedAccept(A a) throws T; /** - * Convenience static factory method for constructing a {@link CheckedEffect1} without an explicit cast or type + * Convenience static factory method for constructing a {@link CheckedEffect} without an explicit cast or type * attribution at the call site. * * @param checkedEffect the checked effect @@ -42,7 +42,7 @@ default void accept(A a) { * @param the input type * @return the checked effect */ - static CheckedEffect1 checked(CheckedEffect1 checkedEffect) { + static CheckedEffect checked(CheckedEffect checkedEffect) { return checkedEffect; } } From 1707283f13a8cc8f690a2005b1b42300172f0d3a Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 21 Aug 2018 20:18:15 -0500 Subject: [PATCH 074/348] inequality functions all take right-hand side argument first --- CHANGELOG.md | 1 + .../lambda/functions/builtin/fn2/GT.java | 12 ++++++------ .../lambda/functions/builtin/fn2/GTE.java | 12 ++++++------ .../lambda/functions/builtin/fn2/LT.java | 12 ++++++------ .../lambda/functions/builtin/fn2/LTE.java | 12 ++++++------ .../lambda/functions/builtin/fn3/GTBy.java | 10 +++++----- .../lambda/functions/builtin/fn3/GTEBy.java | 16 ++++++++-------- .../lambda/functions/builtin/fn3/LTBy.java | 14 +++++++------- .../lambda/functions/builtin/fn3/LTEBy.java | 16 ++++++++-------- .../lambda/iteration/RateLimitingIterator.java | 6 +++--- .../lambda/semigroup/builtin/MaxBy.java | 2 +- .../lambda/semigroup/builtin/MinBy.java | 2 +- .../lambda/functions/builtin/fn2/GTETest.java | 4 ++-- .../lambda/functions/builtin/fn2/GTTest.java | 7 ++++--- .../lambda/functions/builtin/fn2/LTETest.java | 4 ++-- .../lambda/functions/builtin/fn2/LTTest.java | 4 ++-- .../lambda/functions/builtin/fn3/GTByTest.java | 6 +++--- .../lambda/functions/builtin/fn3/GTEByTest.java | 8 ++++---- .../lambda/functions/builtin/fn3/LTByTest.java | 6 +++--- .../lambda/functions/builtin/fn3/LTEByTest.java | 8 ++++---- 20 files changed, 82 insertions(+), 80 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 889c223eb..a70de3724 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - ***Breaking Change***: `Absent` moved to `semigroup.builtin` package - ***Breaking Change***: `Effect#accept()` is now the required method to implement in the functional interface - ***Breaking Change***: `Fn0#apply()` is now the required method to implement in the functional interface +- ***Breaking Change***: `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` take the right-hand side first for more intuitive partial application - `RightAny` overload returns `Monoid` - monoids now all fold with respect to `foldMap` - monoid folding now implicitly starts with the identity, regardless of iterable population diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java index d59094c63..3c45e24cd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java @@ -23,8 +23,8 @@ private GT() { } @Override - public Boolean apply(A x, A y) { - return gtBy(id(), x, y); + public Boolean apply(A y, A x) { + return gtBy(id(), y, x); } @SuppressWarnings("unchecked") @@ -32,11 +32,11 @@ public static > GT gt() { return INSTANCE; } - public static > Predicate gt(A x) { - return GT.gt().apply(x); + public static > Predicate gt(A y) { + return GT.gt().apply(y); } - public static > Boolean gt(A x, A y) { - return gt(x).apply(y); + public static > Boolean gt(A y, A x) { + return gt(y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java index 436285300..23069dd03 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java @@ -23,8 +23,8 @@ private GTE() { } @Override - public Boolean apply(A x, A y) { - return gteBy(id(), x, y); + public Boolean apply(A y, A x) { + return gteBy(id(), y, x); } @SuppressWarnings("unchecked") @@ -32,11 +32,11 @@ public static > GTE gte() { return INSTANCE; } - public static > Predicate gte(A x) { - return GTE.gte().apply(x); + public static > Predicate gte(A y) { + return GTE.gte().apply(y); } - public static > Boolean gte(A x, A y) { - return gte(x).apply(y); + public static > Boolean gte(A y, A x) { + return gte(y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java index f4906bf09..d6a1d6d99 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java @@ -23,8 +23,8 @@ private LT() { } @Override - public Boolean apply(A x, A y) { - return ltBy(id(), x, y); + public Boolean apply(A y, A x) { + return ltBy(id(), y, x); } @SuppressWarnings("unchecked") @@ -32,11 +32,11 @@ public static > LT lt() { return INSTANCE; } - public static > Predicate lt(A x) { - return LT.lt().apply(x); + public static > Predicate lt(A y) { + return LT.lt().apply(y); } - public static > Boolean lt(A x, A y) { - return lt(x).apply(y); + public static > Boolean lt(A y, A x) { + return lt(y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java index 8c0680cbe..19d2424c4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java @@ -23,8 +23,8 @@ private LTE() { } @Override - public Boolean apply(A x, A y) { - return lteBy(id(), x, y); + public Boolean apply(A y, A x) { + return lteBy(id(), y, x); } @SuppressWarnings("unchecked") @@ -32,11 +32,11 @@ public static > LTE lte() { return INSTANCE; } - public static > Predicate lte(A x) { - return LTE.lte().apply(x); + public static > Predicate lte(A y) { + return LTE.lte().apply(y); } - public static > Boolean lte(A x, A y) { - return lte(x).apply(y); + public static > Boolean lte(A y, A x) { + return lte(y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java index e3df534df..4428784e1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java @@ -25,7 +25,7 @@ private GTBy() { } @Override - public Boolean apply(Function compareFn, A x, A y) { + public Boolean apply(Function compareFn, A y, A x) { return compareFn.apply(x).compareTo(compareFn.apply(y)) > 0; } @@ -48,11 +48,11 @@ public static > BiPredicate gtBy(FunctiongtBy().apply(fn); } - public static > Predicate gtBy(Function fn, A x) { - return GTBy.gtBy(fn).apply(x); + public static > Predicate gtBy(Function fn, A y) { + return GTBy.gtBy(fn).apply(y); } - public static > Boolean gtBy(Function fn, A x, A y) { - return gtBy(fn, x).apply(y); + public static > Boolean gtBy(Function fn, A y, A x) { + return gtBy(fn, y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java index bbc26c686..2c5d8ae26 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java @@ -28,8 +28,8 @@ private GTEBy() { } @Override - public Boolean apply(Function compareFn, A x, A y) { - return GTBy.gtBy(compareFn).or(cmpEqBy(compareFn)).apply(x, y); + public Boolean apply(Function compareFn, A y, A x) { + return GTBy.gtBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x); } @Override @@ -38,8 +38,8 @@ public BiPredicate apply(Function compareFn) { } @Override - public Predicate apply(Function compareFn, A x) { - return Fn3.super.apply(compareFn, x)::apply; + public Predicate apply(Function compareFn, A y) { + return Fn3.super.apply(compareFn, y)::apply; } @SuppressWarnings("unchecked") @@ -51,11 +51,11 @@ public static > BiPredicate gteBy(FunctiongteBy().apply(fn); } - public static > Predicate gteBy(Function fn, A x) { - return GTEBy.gteBy(fn).apply(x); + public static > Predicate gteBy(Function fn, A y) { + return GTEBy.gteBy(fn).apply(y); } - public static > Boolean gteBy(Function fn, A x, A y) { - return gteBy(fn, x).apply(y); + public static > Boolean gteBy(Function fn, A y, A x) { + return gteBy(fn, y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java index 5d7b57c79..220a600e8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java @@ -25,7 +25,7 @@ private LTBy() { } @Override - public Boolean apply(Function compareFn, A x, A y) { + public Boolean apply(Function compareFn, A y, A x) { return compareFn.apply(x).compareTo(compareFn.apply(y)) < 0; } @@ -35,8 +35,8 @@ public BiPredicate apply(Function compareFn) { } @Override - public Predicate apply(Function compareFn, A x) { - return Fn3.super.apply(compareFn, x)::apply; + public Predicate apply(Function compareFn, A y) { + return Fn3.super.apply(compareFn, y)::apply; } @SuppressWarnings("unchecked") @@ -48,11 +48,11 @@ public static > BiPredicate ltBy(FunctionltBy().apply(fn); } - public static > Predicate ltBy(Function fn, A x) { - return LTBy.ltBy(fn).apply(x); + public static > Predicate ltBy(Function fn, A y) { + return LTBy.ltBy(fn).apply(y); } - public static > Boolean ltBy(Function fn, A x, A y) { - return ltBy(fn, x).apply(y); + public static > Boolean ltBy(Function fn, A y, A x) { + return ltBy(fn, y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java index 14ea8d6b5..a83fdc9c5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java @@ -28,8 +28,8 @@ private LTEBy() { } @Override - public Boolean apply(Function compareFn, A x, A y) { - return LTBy.ltBy(compareFn).or(cmpEqBy(compareFn)).apply(x, y); + public Boolean apply(Function compareFn, A y, A x) { + return LTBy.ltBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x); } @Override @@ -38,8 +38,8 @@ public BiPredicate apply(Function compareFn) { } @Override - public Predicate apply(Function compareFn, A x) { - return Fn3.super.apply(compareFn, x)::apply; + public Predicate apply(Function compareFn, A y) { + return Fn3.super.apply(compareFn, y)::apply; } @SuppressWarnings("unchecked") @@ -51,11 +51,11 @@ public static > BiPredicate lteBy(FunctionlteBy().apply(fn); } - public static > Predicate lteBy(Function fn, A x) { - return LTEBy.lteBy(fn).apply(x); + public static > Predicate lteBy(Function fn, A y) { + return LTEBy.lteBy(fn).apply(y); } - public static > Boolean lteBy(Function fn, A x, A y) { - return lteBy(fn, x).apply(y); + public static > Boolean lteBy(Function fn, A y, A x) { + return lteBy(fn, y).apply(x); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java index de2e7b94c..f7b622bb8 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java @@ -16,8 +16,8 @@ import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter; -import static com.jnape.palatable.lambda.functions.builtin.fn2.GT.gt; import static com.jnape.palatable.lambda.functions.builtin.fn2.GTE.gte; +import static com.jnape.palatable.lambda.functions.builtin.fn2.LT.lt; import static com.jnape.palatable.lambda.functions.builtin.fn2.LTE.lte; import static com.jnape.palatable.lambda.semigroup.builtin.Max.max; import static java.lang.Thread.sleep; @@ -67,8 +67,8 @@ private boolean rateLimitExhaustedInTimeSlice(Tuple3 { Instant timeSliceEnd = instantSupplier.get(); Instant previousTimeSliceEnd = timeSliceEnd.minus(duration); - timeSlicesForRateLimit.removeIf(gt(previousTimeSliceEnd)); - return max(0L, limit - size(filter(mark -> gte(mark, previousTimeSliceEnd) && lte(mark, timeSliceEnd), timeSlicesForRateLimit))) == 0; + timeSlicesForRateLimit.removeIf(lt(previousTimeSliceEnd)); + return max(0L, limit - size(filter(mark -> lte(mark, previousTimeSliceEnd) && gte(mark, timeSliceEnd), timeSlicesForRateLimit))) == 0; }); } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java index a5bbcce84..5e6cbbe5c 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java @@ -31,7 +31,7 @@ private MaxBy() { @Override public Semigroup apply(Function compareFn) { - return (x, y) -> ltBy(compareFn, x, y) ? y : x; + return (x, y) -> ltBy(compareFn, y, x) ? y : x; } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java index 7803d8ebd..3a7ea9a71 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java @@ -31,7 +31,7 @@ private MinBy() { @Override public Semigroup apply(Function compareFn) { - return (x, y) -> gtBy(compareFn, x, y) ? y : x; + return (x, y) -> gtBy(compareFn, y, x) ? y : x; } @SuppressWarnings("unchecked") diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTETest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTETest.java index 598869ab9..c3fd1f89b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTETest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTETest.java @@ -10,8 +10,8 @@ public class GTETest { @Test public void comparisons() { - assertTrue(gte(2, 1)); + assertTrue(gte(1, 2)); assertTrue(gte(1, 1)); - assertFalse(gte(1, 2)); + assertFalse(gte(2, 1)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTTest.java index 7e73795ea..4f448b695 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTTest.java @@ -2,6 +2,7 @@ import org.junit.Test; +import static com.jnape.palatable.lambda.functions.builtin.fn2.GT.gt; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -9,8 +10,8 @@ public class GTTest { @Test public void comparisons() { - assertTrue(GT.gt(2, 1)); - assertFalse(GT.gt(1, 1)); - assertFalse(GT.gt(1, 2)); + assertTrue(gt(1, 2)); + assertFalse(gt(1, 1)); + assertFalse(gt(2, 1)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTETest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTETest.java index 14ba931c1..8fd684b31 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTETest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTETest.java @@ -10,8 +10,8 @@ public class LTETest { @Test public void comparisons() { - assertTrue(lte(1, 2)); + assertTrue(lte(2, 1)); assertTrue(lte(1, 1)); - assertFalse(lte(2, 1)); + assertFalse(lte(1, 2)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTTest.java index a72ec158f..2c2229aa2 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTTest.java @@ -10,8 +10,8 @@ public class LTTest { @Test public void comparisons() { - assertTrue(lt(1, 2)); + assertTrue(lt(2, 1)); assertFalse(lt(1, 1)); - assertFalse(lt(2, 1)); + assertFalse(lt(1, 2)); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTByTest.java index 20e0c4e2a..a04ffb0b6 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTByTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTByTest.java @@ -11,10 +11,10 @@ public class GTByTest { @Test public void comparisons() { - assertTrue(gtBy(id(), 2, 1)); + assertTrue(gtBy(id(), 1, 2)); assertFalse(gtBy(id(), 1, 1)); - assertFalse(gtBy(id(), 1, 2)); + assertFalse(gtBy(id(), 2, 1)); - assertTrue(gtBy(String::length, "aaa", "bb")); + assertTrue(gtBy(String::length, "bb", "aaa")); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEByTest.java index f363ccb34..438d0cb84 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEByTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEByTest.java @@ -11,11 +11,11 @@ public class GTEByTest { @Test public void comparisons() { - assertTrue(gteBy(id(), 2, 1)); + assertTrue(gteBy(id(), 1, 2)); assertTrue(gteBy(id(), 1, 1)); - assertFalse(gteBy(id(), 1, 2)); + assertFalse(gteBy(id(), 2, 1)); - assertTrue(gteBy(String::length, "ab", "b")); - assertTrue(gteBy(String::length, "ab", "bc")); + assertTrue(gteBy(String::length, "b", "ab")); + assertTrue(gteBy(String::length, "bc", "ab")); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTByTest.java index c06db00b9..dc511d7cf 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTByTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTByTest.java @@ -11,10 +11,10 @@ public class LTByTest { @Test public void comparisons() { - assertTrue(ltBy(id(), 1, 2)); + assertTrue(ltBy(id(), 2, 1)); assertFalse(ltBy(id(), 1, 1)); - assertFalse(ltBy(id(), 2, 1)); + assertFalse(ltBy(id(), 1, 2)); - assertTrue(ltBy(String::length, "b", "ab")); + assertTrue(ltBy(String::length, "ab", "b")); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEByTest.java index 44cc71ef5..122c76070 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEByTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEByTest.java @@ -11,11 +11,11 @@ public class LTEByTest { @Test public void comparisons() { - assertTrue(lteBy(id(), 1, 2)); + assertTrue(lteBy(id(), 2, 1)); assertTrue(lteBy(id(), 1, 1)); - assertFalse(lteBy(id(), 2, 1)); + assertFalse(lteBy(id(), 1, 2)); - assertTrue(lteBy(String::length, "b", "ab")); - assertTrue(lteBy(String::length, "bc", "ab")); + assertTrue(lteBy(String::length, "ab", "b")); + assertTrue(lteBy(String::length, "ab", "bc")); } } \ No newline at end of file From 36f8abdb30212da441cfe3a92e6e1ad14db05162 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 23 Aug 2018 14:25:52 -0500 Subject: [PATCH 075/348] Fixing javadoc on Effect --- .../com/jnape/palatable/lambda/functions/Effect.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index ead5d645f..f9adebe97 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -5,16 +5,15 @@ import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Unit.UNIT; /** - * A function taking "no arguments", implemented as an {@link Fn1}<{@link Unit}, A>. + * A function returning "no result", and therefore only useful as a side-effect. * - * @param the result type - * @see Fn1 - * @see Supplier + * @param the argument type + * @see Fn0 + * @see Consumer */ @FunctionalInterface public interface Effect extends Fn1, Consumer { From f978218ab8fcb1eed1ee216b112176e32cbae7a4 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 2 Sep 2018 15:06:10 -0500 Subject: [PATCH 076/348] deprecating dyadic Either#flatMap in favor of match --- CHANGELOG.md | 1 + src/main/java/com/jnape/palatable/lambda/adt/Either.java | 6 ++++-- .../palatable/lambda/semigroup/builtin/LeftAll.java | 2 +- .../palatable/lambda/semigroup/builtin/LeftAny.java | 6 +++--- .../palatable/lambda/semigroup/builtin/RightAny.java | 6 +++--- .../java/com/jnape/palatable/lambda/adt/EitherTest.java | 9 --------- 6 files changed, 12 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a70de3724..0667f1a50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Deprecated - `AddAll` semigroup, in favor of the monoid that no longer mutates any argument +- Dyadic `Either#flatMap()`, in favor of `Either#match` ## [3.1.0] - 2018-07-16 ### Added 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 d9c9d2fa1..27d3408bd 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -123,7 +123,7 @@ public final Either filter(Function pred, */ @Override public Either flatMap(Function>> rightFn) { - return flatMap(Either::left, rightFn.andThen(Applicative::coerce)); + return match(Either::left, rightFn.andThen(Applicative::coerce)); } /** @@ -136,7 +136,9 @@ public Either flatMap(Function 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 + * @deprecated in favor of {@link Either#match(Function, Function)} */ + @Deprecated public final Either flatMap(Function> leftFn, Function> rightFn) { return match(leftFn, rightFn); @@ -144,7 +146,7 @@ public final Either flatMap(Function invert() { - return flatMap(Either::right, Either::left); + return match(Either::right, Either::left); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java index 70ef187fd..b8955b2e0 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java @@ -37,7 +37,7 @@ private LeftAll() { @Override public Semigroup> apply(Semigroup lSemigroup) { - return (x, y) -> x.flatMap(xL -> y.flatMap(yL -> left(lSemigroup.apply(xL, yL)), Either::right), Either::right); + return (x, y) -> x.match(xL -> y.match(yL -> left(lSemigroup.apply(xL, yL)), Either::right), Either::right); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java index 1bc166dca..b93133143 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java @@ -36,9 +36,9 @@ private LeftAny() { @Override public Semigroup> apply(Semigroup lSemigroup) { - return (x, y) -> x.flatMap(xL -> y.flatMap(yL -> left(lSemigroup.apply(xL, yL)), - yR -> left(xL)), - xR -> y); + return (x, y) -> x.match(xL -> y.match(yL -> left(lSemigroup.apply(xL, yL)), + yR -> left(xL)), + xR -> y); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java index 04531cbfb..00f528054 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java @@ -37,9 +37,9 @@ private RightAny() { @Override public Semigroup> apply(Semigroup rSemigroup) { - return (x, y) -> x.flatMap(constantly(y), - xR -> y.flatMap(constantly(right(xR)), - rSemigroup.apply(xR).andThen(Either::right))); + return (x, y) -> x.match(constantly(y), + xR -> y.match(constantly(right(xR)), + rSemigroup.apply(xR).andThen(Either::right))); } @SuppressWarnings("unchecked") diff --git a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java index a06282ba6..e43e2438f 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java @@ -110,15 +110,6 @@ public void monadicFlatMapLiftsRightAndFlattensBackToEither() { assertThat(right.flatMap(r -> right(r + 1)), is(right(2))); } - @Test - public void dyadicFlatMapDuallyLiftsAndFlattensBackToEither() { - Either left = left("foo"); - Either right = right(1); - - assertThat(left.flatMap(l -> left(l + "bar"), r -> right(r + 1)), is(left("foobar"))); - assertThat(right.flatMap(l -> left(l + "bar"), r -> right(r + 1)), is(right(2))); - } - @Test public void mergeDuallyLiftsAndCombinesBiasingLeft() { Either left1 = left("foo"); From ba86af4df13cae82e129e469e58bc78273db9a7b Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 2 Sep 2018 16:34:08 -0500 Subject: [PATCH 077/348] simpler default discardR --- .../java/com/jnape/palatable/lambda/functor/Applicative.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java index 224963a83..c8eb56d7c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java @@ -73,7 +73,7 @@ default Applicative discardL(Applicative appB) { * @return this Applicative */ default Applicative discardR(Applicative appB) { - return appB.zip(zip(pure(constantly()))); + return appB.zip(fmap(constantly())); } /** From 17e87623b627721cf84853cbae109fcc9453de3c Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 16 Sep 2018 15:44:44 -0500 Subject: [PATCH 078/348] Adding LiftA3-LiftA8 --- CHANGELOG.md | 1 + .../lambda/functions/builtin/fn3/LiftA2.java | 2 +- .../lambda/functions/builtin/fn4/LiftA3.java | 87 ++++++++ .../lambda/functions/builtin/fn5/LiftA4.java | 108 ++++++++++ .../lambda/functions/builtin/fn6/LiftA5.java | 132 +++++++++++++ .../lambda/functions/builtin/fn7/LiftA6.java | 162 +++++++++++++++ .../lambda/functions/builtin/fn8/LiftA7.java | 186 ++++++++++++++++++ .../functions/builtin/fn4/LiftA3Test.java | 15 ++ .../functions/builtin/fn5/LiftA4Test.java | 15 ++ .../functions/builtin/fn6/LiftA5Test.java | 15 ++ .../functions/builtin/fn7/LiftA6Test.java | 15 ++ .../functions/builtin/fn8/LiftA7Test.java | 15 ++ 12 files changed, 752 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7Test.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0667f1a50..87acd6d70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Tuple2-8` specializations of left/right product rotation - `CheckedEffect`, an `Effect` variant that can throw checked exceptions - `CheckedFn1#checked`, convenience static factory method to aid inference +- `LiftA3-8`, higher-arity analogs to `LiftA2` ### Deprecated - `AddAll` semigroup, in favor of the monoid that no longer mutates any argument diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java index 51381ef58..7ba773691 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java @@ -12,7 +12,7 @@ * {@link Applicative} context. Functionally equivalent to appB.zip(appA.fmap(fn)). * * @param the function's first argument type - * @param the function's second argument typ + * @param the function's second argument type * @param the function's return type * @param the applicative unification type * @param the inferred first applicative argument type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java new file mode 100644 index 000000000..a34a1aaae --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java @@ -0,0 +1,87 @@ +package com.jnape.palatable.lambda.functions.builtin.fn4; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.Fn4; +import com.jnape.palatable.lambda.functor.Applicative; + +/** + * Lift into and apply an {@link Fn3} to three {@link Applicative} values, returning the result inside the same + * {@link Applicative} context. + * + * @param the function's first argument type + * @param the function's second argument type + * @param the function's third argument type + * @param the function's return type + * @param the applicative unification type + * @param the inferred first applicative argument type + * @param the inferred second applicative argument type + * @param the inferred third applicative argument type + * @param the inferred applicative return type + * @see Applicative#zip(Applicative) + */ +public final class LiftA3, + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative> implements Fn4, AppA, AppB, AppC, AppD> { + + private static final LiftA3 INSTANCE = new LiftA3(); + + private LiftA3() { + } + + @Override + public AppD apply(Fn3 fn, AppA appA, AppB appB, AppC appC) { + return appC.zip(appB.zip(appA.fmap(fn))).coerce(); + } + + @SuppressWarnings("unchecked") + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative> LiftA3 liftA3() { + return INSTANCE; + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative> Fn3 liftA3(Fn3 fn) { + return LiftA3.liftA3().apply(fn); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative> Fn2 liftA3(Fn3 fn, AppA appA) { + return LiftA3.liftA3(fn).apply(appA); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative> Fn1 liftA3(Fn3 fn, AppA appA, AppB appB) { + return LiftA3.liftA3(fn, appA).apply(appB); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative> AppD liftA3(Fn3 fn, AppA appA, AppB appB, + AppC appC) { + return LiftA3.liftA3(fn, appA, appB).apply(appC); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java new file mode 100644 index 000000000..099d519ca --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java @@ -0,0 +1,108 @@ +package com.jnape.palatable.lambda.functions.builtin.fn5; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.Fn4; +import com.jnape.palatable.lambda.functions.Fn5; +import com.jnape.palatable.lambda.functor.Applicative; + +/** + * Lift into and apply an {@link Fn4} to four {@link Applicative} values, returning the result inside the same + * {@link Applicative} context. + * + * @param the function's first argument type + * @param the function's second argument type + * @param the function's third argument type + * @param the function's fourth argument type + * @param the function's return type + * @param the applicative unification type + * @param the inferred first applicative argument type + * @param the inferred second applicative argument type + * @param the inferred third applicative argument type + * @param the inferred fourth applicative argument type + * @param the inferred applicative return type + * @see Applicative#zip(Applicative) + */ +public final class LiftA4, + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative> implements Fn5, AppA, AppB, AppC, AppD, AppE> { + + private static final LiftA4 INSTANCE = new LiftA4(); + + private LiftA4() { + } + + @Override + public AppE apply(Fn4 fn, AppA appA, AppB appB, AppC appC, AppD appD) { + return appD.zip(appC.zip(appB.zip(appA.fmap(fn)))).coerce(); + } + + @SuppressWarnings("unchecked") + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative> LiftA4 liftA4() { + return INSTANCE; + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative> Fn4 liftA4(Fn4 fn) { + return LiftA4.liftA4().apply(fn); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative> Fn3 liftA4(Fn4 fn, AppA appA) { + return LiftA4.liftA4(fn).apply(appA); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative> Fn2 liftA4(Fn4 fn, AppA appA, + AppB appB) { + return LiftA4.liftA4(fn, appA).apply(appB); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative> Fn1 liftA4(Fn4 fn, AppA appA, AppB appB, + AppC appC) { + return LiftA4.liftA4(fn, appA, appB).apply(appC); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative> AppE liftA4(Fn4 fn, AppA appA, AppB appB, + AppC appC, AppD appD) { + return LiftA4.liftA4(fn, appA, appB, appC).apply(appD); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java new file mode 100644 index 000000000..f32d44569 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java @@ -0,0 +1,132 @@ +package com.jnape.palatable.lambda.functions.builtin.fn6; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.Fn4; +import com.jnape.palatable.lambda.functions.Fn5; +import com.jnape.palatable.lambda.functions.Fn6; +import com.jnape.palatable.lambda.functor.Applicative; + +/** + * Lift into and apply an {@link Fn5} to five {@link Applicative} values, returning the result inside the same + * {@link Applicative} context. + * + * @param the function's first argument type + * @param the function's second argument type + * @param the function's third argument type + * @param the function's fourth argument type + * @param the function's fifth argument type + * @param the function's return type + * @param the applicative unification type + * @param the inferred first applicative argument type + * @param the inferred second applicative argument type + * @param the inferred third applicative argument type + * @param the inferred fourth applicative argument type + * @param the inferred fifth applicative argument type + * @param the inferred applicative return type + * @see Applicative#zip(Applicative) + */ +public final class LiftA5, + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative> implements Fn6, AppA, AppB, AppC, AppD, AppE, AppF> { + + private static final LiftA5 INSTANCE = new LiftA5(); + + private LiftA5() { + } + + @Override + public AppF apply(Fn5 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE) { + return appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn))))).coerce(); + } + + @SuppressWarnings("unchecked") + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative> LiftA5 liftA5() { + return INSTANCE; + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative> Fn5 liftA5(Fn5 fn) { + return LiftA5.liftA5().apply(fn); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative> Fn4 liftA5(Fn5 fn, + AppA appA) { + return LiftA5.liftA5(fn).apply(appA); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative> Fn3 liftA5(Fn5 fn, AppA appA, + AppB appB) { + return LiftA5.liftA5(fn, appA).apply(appB); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative> Fn2 liftA5(Fn5 fn, AppA appA, + AppB appB, + AppC appC) { + return LiftA5.liftA5(fn, appA, appB).apply(appC); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative> Fn1 liftA5(Fn5 fn, AppA appA, AppB appB, + AppC appC, AppD appD) { + return LiftA5.liftA5(fn, appA, appB, appC).apply(appD); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative> AppF liftA5(Fn5 fn, AppA appA, AppB appB, + AppC appC, AppD appD, AppE appE) { + return LiftA5.liftA5(fn, appA, appB, appC, appD).apply(appE); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java new file mode 100644 index 000000000..72da45314 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java @@ -0,0 +1,162 @@ +package com.jnape.palatable.lambda.functions.builtin.fn7; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.Fn4; +import com.jnape.palatable.lambda.functions.Fn5; +import com.jnape.palatable.lambda.functions.Fn6; +import com.jnape.palatable.lambda.functions.Fn7; +import com.jnape.palatable.lambda.functor.Applicative; + +/** + * Lift into and apply an {@link Fn6} to six {@link Applicative} values, returning the result inside the same + * {@link Applicative} context. + * + * @param the function's first argument type + * @param the function's second argument type + * @param the function's third argument type + * @param the function's fourth argument type + * @param the function's fifth argument type + * @param the function's sixth argument type + * @param the function's return type + * @param the applicative unification type + * @param the inferred first applicative argument type + * @param the inferred second applicative argument type + * @param the inferred third applicative argument type + * @param the inferred fourth applicative argument type + * @param the inferred fifth applicative argument type + * @param the inferred sixth applicative argument type + * @param the inferred applicative return type + * @see Applicative#zip(Applicative) + */ +public final class LiftA6, + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative> implements Fn7, AppA, AppB, AppC, AppD, AppE, AppF, AppG> { + + private static final LiftA6 INSTANCE = new LiftA6(); + + private LiftA6() { + } + + @Override + public AppG apply(Fn6 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, + AppF appF) { + return appF.zip(appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn)))))).coerce(); + } + + + @SuppressWarnings("unchecked") + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative> LiftA6 liftA6() { + return INSTANCE; + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative> Fn6 liftA6( + Fn6 fn) { + return LiftA6.liftA6().apply(fn); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative> Fn5 liftA6( + Fn6 fn, + AppA appA) { + return LiftA6.liftA6(fn).apply(appA); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative> Fn4 liftA6(Fn6 fn, + AppA appA, + AppB appB) { + return LiftA6.liftA6(fn, appA).apply(appB); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative> Fn3 liftA6(Fn6 fn, AppA appA, + AppB appB, + AppC appC) { + return LiftA6.liftA6(fn, appA, appB).apply(appC); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative> Fn2 liftA6(Fn6 fn, AppA appA, + AppB appB, + AppC appC, AppD appD) { + return LiftA6.liftA6(fn, appA, appB, appC).apply(appD); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative> Fn1 liftA6(Fn6 fn, AppA appA, AppB appB, + AppC appC, AppD appD, AppE appE) { + return LiftA6.liftA6(fn, appA, appB, appC, appD).apply(appE); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative> AppG liftA6(Fn6 fn, AppA appA, AppB appB, + AppC appC, AppD appD, AppE appE, AppF appF) { + return LiftA6.liftA6(fn, appA, appB, appC, appD, appE).apply(appF); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java new file mode 100644 index 000000000..6d508f06d --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java @@ -0,0 +1,186 @@ +package com.jnape.palatable.lambda.functions.builtin.fn8; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.Fn4; +import com.jnape.palatable.lambda.functions.Fn5; +import com.jnape.palatable.lambda.functions.Fn6; +import com.jnape.palatable.lambda.functions.Fn7; +import com.jnape.palatable.lambda.functions.Fn8; +import com.jnape.palatable.lambda.functor.Applicative; + +/** + * Lift into and apply an {@link Fn7} to seven {@link Applicative} values, returning the result inside the same + * {@link Applicative} context. + * + * @param the function's first argument type + * @param the function's second argument type + * @param the function's third argument type + * @param the function's fourth argument type + * @param the function's fifth argument type + * @param the function's sixth argument type + * @param the function's seventh argument type + * @param the function's return type + * @param the applicative unification type + * @param the inferred first applicative argument type + * @param the inferred second applicative argument type + * @param the inferred third applicative argument type + * @param the inferred fourth applicative argument type + * @param the inferred fifth applicative argument type + * @param the inferred sixth applicative argument type + * @param the inferred seventh applicative argument type + * @param the inferred applicative return type + * @see Applicative#zip(Applicative) + */ +public final class LiftA7, + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> implements Fn8, AppA, AppB, AppC, AppD, AppE, AppF, AppG, AppH> { + + private static final LiftA7 INSTANCE = new LiftA7(); + + private LiftA7() { + } + + @Override + public AppH apply(Fn7 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, + AppF appF, AppG appG) { + return appG.zip(appF.zip(appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn))))))).coerce(); + } + + @SuppressWarnings("unchecked") + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> LiftA7 liftA7() { + return INSTANCE; + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> Fn7 liftA7( + Fn7 fn) { + return LiftA7.liftA7().apply(fn); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> Fn6 liftA7( + Fn7 fn, AppA appA) { + return LiftA7.liftA7(fn).apply(appA); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> Fn5 liftA7( + Fn7 fn, AppA appA, AppB appB) { + return LiftA7.liftA7(fn, appA).apply(appB); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> Fn4 liftA7(Fn7 fn, + AppA appA, AppB appB, + AppC appC) { + return LiftA7.liftA7(fn, appA, appB).apply(appC); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> Fn3 liftA7(Fn7 fn, + AppA appA, AppB appB, AppC appC, + AppD appD) { + return LiftA7.liftA7(fn, appA, appB, appC).apply(appD); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> Fn2 liftA7(Fn7 fn, AppA appA, + AppB appB, AppC appC, AppD appD, AppE appE) { + return LiftA7.liftA7(fn, appA, appB, appC, appD).apply(appE); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> Fn1 liftA7(Fn7 fn, AppA appA, + AppB appB, AppC appC, AppD appD, AppE appE, + AppF appF) { + return LiftA7.liftA7(fn, appA, appB, appC, appD, appE).apply(appF); + } + + public static , + AppB extends Applicative, + AppC extends Applicative, + AppD extends Applicative, + AppE extends Applicative, + AppF extends Applicative, + AppG extends Applicative, + AppH extends Applicative> AppH liftA7(Fn7 fn, AppA appA, AppB appB, + AppC appC, AppD appD, AppE appE, AppF appF, AppG appG) { + return LiftA7.liftA7(fn, appA, appB, appC, appD, appE, appF).apply(appG); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3Test.java new file mode 100644 index 000000000..e6f65f814 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3Test.java @@ -0,0 +1,15 @@ +package com.jnape.palatable.lambda.functions.builtin.fn4; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functions.builtin.fn4.LiftA3.liftA3; +import static org.junit.Assert.assertEquals; + +public class LiftA3Test { + + @Test + public void lifting() { + assertEquals(just(6), liftA3((a, b, c) -> a + b + c, just(1), just(2), just(3))); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4Test.java new file mode 100644 index 000000000..784e04fb6 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4Test.java @@ -0,0 +1,15 @@ +package com.jnape.palatable.lambda.functions.builtin.fn5; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functions.builtin.fn5.LiftA4.liftA4; +import static org.junit.Assert.assertEquals; + +public class LiftA4Test { + + @Test + public void lifting() { + assertEquals(just(10), liftA4((a, b, c, d) -> a + b + c + d, just(1), just(2), just(3), just(4))); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5Test.java new file mode 100644 index 000000000..0d1851d34 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5Test.java @@ -0,0 +1,15 @@ +package com.jnape.palatable.lambda.functions.builtin.fn6; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functions.builtin.fn6.LiftA5.liftA5; +import static org.junit.Assert.assertEquals; + +public class LiftA5Test { + + @Test + public void lifting() { + assertEquals(just(15), liftA5((a, b, c, d, e) -> a + b + c + d + e, just(1), just(2), just(3), just(4), just(5))); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6Test.java new file mode 100644 index 000000000..a247e5620 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6Test.java @@ -0,0 +1,15 @@ +package com.jnape.palatable.lambda.functions.builtin.fn7; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functions.builtin.fn7.LiftA6.liftA6; +import static org.junit.Assert.assertEquals; + +public class LiftA6Test { + + @Test + public void lifting() { + assertEquals(just(21), liftA6((a, b, c, d, e, f) -> a + b + c + d + e + f, just(1), just(2), just(3), just(4), just(5), just(6))); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7Test.java new file mode 100644 index 000000000..73297afde --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7Test.java @@ -0,0 +1,15 @@ +package com.jnape.palatable.lambda.functions.builtin.fn8; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functions.builtin.fn8.LiftA7.liftA7; +import static org.junit.Assert.assertEquals; + +public class LiftA7Test { + + @Test + public void lifting() { + assertEquals(just(28), liftA7((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g, just(1), just(2), just(3), just(4), just(5), just(6), just(7))); + } +} \ No newline at end of file From 94aa2bcd9546395daf3a694c886cec35878a5a80 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 16 Sep 2018 15:47:33 -0500 Subject: [PATCH 079/348] Either#diverge returns a Choice3 --- CHANGELOG.md | 1 + src/main/java/com/jnape/palatable/lambda/adt/Either.java | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87acd6d70..e9c473ec7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - monoid folding now implicitly starts with the identity, regardless of iterable population - `Concat` monoid can now fold infinite iterables - all `Function` are now `Function` for better compatibility +- `Either#diverge` returns a `Choice3` ### Added - `Predicate#predicate` static factory method 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 27d3408bd..dfcb85973 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.adt; +import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek2; @@ -204,6 +205,11 @@ public Either peek(Consumer leftConsumer, Consumer rightConsumer) { @Override public abstract V match(Function leftFn, Function rightFn); + @Override + public Choice3 diverge() { + return match(Choice3::a, Choice3::b); + } + @Override public final Either fmap(Function fn) { return Monad.super.fmap(fn).coerce(); From 774d5b090c569ba27246caaf90f19c638c513e5a Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 6 Oct 2018 17:12:44 -0500 Subject: [PATCH 080/348] Adding Alter for applying an effect to an input and returning it --- CHANGELOG.md | 3 +- .../lambda/functions/builtin/fn2/Alter.java | 39 +++++++++++++++++++ .../functions/builtin/fn2/AlterTest.java | 20 ++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index e9c473ec7..fa46dde2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Tuple2-8` specializations of left/right product rotation - `CheckedEffect`, an `Effect` variant that can throw checked exceptions - `CheckedFn1#checked`, convenience static factory method to aid inference -- `LiftA3-8`, higher-arity analogs to `LiftA2` +- `LiftA3-8`, higher-arity analogs to `LiftA2` +- `Alter`, for applying an `Effect` to an input and returning it, presumably altered ### Deprecated - `AddAll` semigroup, in favor of the monoid that no longer mutates any argument diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java new file mode 100644 index 000000000..5b122c5ff --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -0,0 +1,39 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.Effect; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; + +/** + * Given an {@link Effect}<A> and some A, perform the effect on the A and + * return it. + * + * @param the input and output + */ +public final class Alter implements Fn2, A, A> { + + private static final Alter INSTANCE = new Alter(); + + private Alter() { + } + + @Override + public A apply(Effect effect, A a) { + return effect.fmap(constantly(a)).apply(a); + } + + @SuppressWarnings("unchecked") + public static Alter alter() { + return INSTANCE; + } + + public static Fn1 alter(Effect effect) { + return Alter.alter().apply(effect); + } + + public static A alter(Effect effect, A a) { + return Alter.alter(effect).apply(a); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java new file mode 100644 index 000000000..8a8031f61 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import java.util.ArrayList; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.Alter.alter; +import static java.util.Collections.singletonList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; + +public class AlterTest { + + @Test + public void altersInput() { + ArrayList input = new ArrayList<>(); + assertSame(input, alter(xs -> xs.add("foo"), input)); + assertEquals(singletonList("foo"), input); + } +} \ No newline at end of file From d6ac5bb7c7062a9cb4877c354818749b3e91d3e0 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 21 Oct 2018 17:16:30 -0500 Subject: [PATCH 081/348] Maybe is now a coproduct of Unit and A --- CHANGELOG.md | 3 +- .../com/jnape/palatable/lambda/adt/Maybe.java | 110 ++++++++++-------- .../jnape/palatable/lambda/adt/MaybeTest.java | 22 ++++ 3 files changed, 87 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa46dde2e..3005acef9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - monoid folding now implicitly starts with the identity, regardless of iterable population - `Concat` monoid can now fold infinite iterables - all `Function` are now `Function` for better compatibility -- `Either#diverge` returns a `Choice3` +- `Either#diverge` returns a `Choice3` +- `Maybe` is now a `CoProduct2` of `Unit` and `A` ### Added - `Predicate#predicate` static factory method diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index 93a700061..ad0b81ad9 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -1,5 +1,10 @@ package com.jnape.palatable.lambda.adt; +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.adt.choice.Choice3; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functor.Applicative; @@ -14,6 +19,9 @@ import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; /** * The optional type, representing a potentially absent value. This is lambda's analog of {@link Optional}, supporting @@ -22,7 +30,8 @@ * @param the optional parameter type * @see Optional */ -public abstract class Maybe implements Monad, Traversable { +public abstract class Maybe implements CoProduct2>, Monad, Traversable { + private Maybe() { } @@ -32,7 +41,9 @@ private Maybe() { * @param otherSupplier the supplier for the other value * @return this value, or the supplied other value */ - public abstract A orElseGet(Supplier otherSupplier); + public final A orElseGet(Supplier otherSupplier) { + return match(__ -> otherSupplier.get(), id()); + } /** * If the value is present, return it; otherwise, return other. @@ -130,7 +141,24 @@ public final Maybe discardR(Applicative appB) { } @Override - public abstract Maybe flatMap(Function> f); + public final Maybe flatMap(Function> f) { + return match(constantly(nothing()), f.andThen(Applicative::coerce)); + } + + @Override + public Choice3 diverge() { + return match(Choice3::a, Choice3::b); + } + + @Override + public Tuple2, Maybe> project() { + return CoProduct2.super.project().into(HList::tuple); + } + + @Override + public Choice2 invert() { + return match(Choice2::b, Choice2::a); + } /** * If this value is present, accept it by consumer; otherwise, do nothing. @@ -142,6 +170,14 @@ public final Maybe peek(Consumer consumer) { return Peek.peek(consumer, this); } + @Override + @SuppressWarnings("unchecked") + public final , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( + Function fn, + Function pure) { + return match(__ -> pure.apply((TravB) Maybe.nothing()), a -> (AppTrav) fn.apply(a).fmap(Maybe::just)); + } + /** * Convenience static factory method for creating a {@link Maybe} from an {@link Either}. If either is * a right value, wrap the value in a just and return it; otherwise, return {@link #nothing()}. @@ -192,80 +228,60 @@ public static Maybe just(A a) { return new Just<>(a); } + /** + * Return nothing. + * + * @param the type of the value, if there was one + * @return nothing + */ @SuppressWarnings("unchecked") public static Maybe nothing() { return Nothing.INSTANCE; } - private static final class Just extends Maybe { - - private final A a; - - private Just(A a) { - this.a = a; - } - - @Override - public A orElseGet(Supplier otherSupplier) { - return a; - } - - @Override - public Maybe flatMap(Function> f) { - return f.apply(a).coerce(); - } - - @Override - @SuppressWarnings("unchecked") - public , - AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { - return fn.apply(a).fmap(Just::new).fmap(Applicative::coerce).coerce(); - } + private static final class Nothing extends Maybe { + private static final Nothing INSTANCE = new Nothing(); - @Override - public boolean equals(Object other) { - return other instanceof Just && Objects.equals(this.a, ((Just) other).a); + private Nothing() { } @Override - public int hashCode() { - return Objects.hash(a); + public R match(Function aFn, Function bFn) { + return aFn.apply(UNIT); } @Override public String toString() { - return "Just " + a; + return "Nothing"; } } - private static final class Nothing extends Maybe { - private static final Nothing INSTANCE = new Nothing(); + private static final class Just extends Maybe { - private Nothing() { + private final A a; + + private Just(A a) { + this.a = a; } @Override - @SuppressWarnings("unchecked") - public Maybe flatMap(Function> f) { - return nothing(); + public R match(Function aFn, Function bFn) { + return bFn.apply(a); } @Override - @SuppressWarnings("unchecked") - public , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { - return pure.apply((TravB) nothing()); + public boolean equals(Object other) { + return other instanceof Just && Objects.equals(this.a, ((Just) other).a); } @Override - public A orElseGet(Supplier otherSupplier) { - return otherSupplier.get(); + public int hashCode() { + return Objects.hash(a); } @Override public String toString() { - return "Nothing"; + return "Just " + a; } } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java index 9205db543..1e747dc34 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java @@ -1,5 +1,7 @@ package com.jnape.palatable.lambda.adt; +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -17,6 +19,8 @@ import static com.jnape.palatable.lambda.adt.Either.right; 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.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -108,4 +112,22 @@ public void justOrThrow() { public void nothingOrThrow() { nothing().orElseThrow(IllegalStateException::new); } + + @Test + public void divergesIntoChoice3() { + assertEquals(Choice3.a(UNIT), nothing().diverge()); + assertEquals(Choice3.b(1), just(1).diverge()); + } + + @Test + public void projectsIntoTuple2() { + assertEquals(tuple(just(UNIT), nothing()), nothing().project()); + assertEquals(tuple(nothing(), just(1)), just(1).project()); + } + + @Test + public void invertsIntoChoice2() { + assertEquals(Choice2.b(UNIT), nothing().invert()); + assertEquals(Choice2.a(1), just(1).invert()); + } } \ No newline at end of file From 6fed0ab2e785d628c0dfae9316ab53b3e8a980f2 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 25 Oct 2018 00:51:46 -0500 Subject: [PATCH 082/348] Adding Between and Clamp --- CHANGELOG.md | 2 + .../lambda/functions/builtin/fn3/Between.java | 43 +++++++++++++++++ .../lambda/functions/builtin/fn3/Clamp.java | 46 +++++++++++++++++++ .../functions/builtin/fn3/BetweenTest.java | 19 ++++++++ .../functions/builtin/fn3/ClampTest.java | 16 +++++++ 5 files changed, 126 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BetweenTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ClampTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3005acef9..abfce5dad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `CheckedFn1#checked`, convenience static factory method to aid inference - `LiftA3-8`, higher-arity analogs to `LiftA2` - `Alter`, for applying an `Effect` to an input and returning it, presumably altered +- `Clamp`, for clamping a value between two bounds +- `Between`, for determining if a value is in a closed interval ### Deprecated - `AddAll` semigroup, in favor of the monoid that no longer mutates any argument diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java new file mode 100644 index 000000000..70dac2bce --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java @@ -0,0 +1,43 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Clamp.clamp; + +/** + * Given two bounds and a value, return whether or not the value is greater than or equal to the lower bound and less + * than or equal to the upper bound. + * + * @param the bounds and input type + */ +public final class Between> implements Fn3 { + + private static final Between INSTANCE = new Between<>(); + + private Between() { + } + + @Override + public Boolean apply(A lower, A upper, A a) { + return clamp(lower, upper, a).equals(a); + } + + @SuppressWarnings("unchecked") + public static > Between between() { + return INSTANCE; + } + + public static > BiPredicate between(A lower) { + return Between.between().apply(lower)::apply; + } + + public static > Predicate between(A lower, A upper) { + return between(lower).apply(upper); + } + + public static > Boolean between(A lower, A upper, A a) { + return between(lower, upper).apply(a); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java new file mode 100644 index 000000000..62d0c21de --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java @@ -0,0 +1,46 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; + +import static com.jnape.palatable.lambda.semigroup.builtin.Max.max; +import static com.jnape.palatable.lambda.semigroup.builtin.Min.min; + +/** + * Given two bounds and a value, "clamp" the value between the bounds via the following algorithm: + * - if the value is strictly less than the lower bound, return the lower bound + * - if the value is strictly greater than the upper bound, return the upper bound + * - otherwise, return the value + * + * @param the bounds and input type + */ +public final class Clamp> implements Fn3 { + + private static final Clamp INSTANCE = new Clamp<>(); + + private Clamp() { + } + + @Override + public A apply(A lower, A upper, A a) { + return max(min(lower, upper)).fmap(min(max(lower, upper))).apply(a); + } + + @SuppressWarnings("unchecked") + public static > Clamp clamp() { + return INSTANCE; + } + + public static > Fn2 clamp(A lower) { + return Clamp.clamp().apply(lower); + } + + public static > Fn1 clamp(A lower, A upper) { + return clamp(lower).apply(upper); + } + + public static > A clamp(A lower, A upper, A a) { + return clamp(lower, upper).apply(a); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BetweenTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BetweenTest.java new file mode 100644 index 000000000..2638ee7f1 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BetweenTest.java @@ -0,0 +1,19 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Between.between; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class BetweenTest { + + @Test + public void testsIfValueIsBetweenClosedBounds() { + assertFalse(between(1, 10, 0)); + assertTrue(between(1, 10, 1)); + assertTrue(between(1, 10, 5)); + assertTrue(between(1, 10, 10)); + assertFalse(between(1, 10, 11)); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ClampTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ClampTest.java new file mode 100644 index 000000000..9b2bedde4 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ClampTest.java @@ -0,0 +1,16 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Clamp.clamp; +import static org.junit.Assert.assertEquals; + +public class ClampTest { + + @Test + public void clampsValueBetweenBounds() { + assertEquals((Integer) 5, clamp(1, 10, 5)); + assertEquals((Integer) 1, clamp(1, 10, -1)); + assertEquals((Integer) 10, clamp(1, 10, 11)); + } +} From 1e7ab1f0b36f6defee58fc1dec1abea4fdb094db Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 3 Nov 2018 22:33:35 -0500 Subject: [PATCH 083/348] Fn0 is now Callable --- CHANGELOG.md | 3 ++- .../com/jnape/palatable/lambda/functions/Fn0.java | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abfce5dad..1f1c0c6f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Concat` monoid can now fold infinite iterables - all `Function` are now `Function` for better compatibility - `Either#diverge` returns a `Choice3` -- `Maybe` is now a `CoProduct2` of `Unit` and `A` +- `Maybe` is now a `CoProduct2` of `Unit` and `A` +- `Fn0` now additionally implements `Callable` ### Added - `Predicate#predicate` static factory method diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index 357a28a3c..023f531c3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; +import java.util.concurrent.Callable; import java.util.function.Function; import java.util.function.Supplier; @@ -16,9 +17,10 @@ * @param the result type * @see Fn1 * @see Supplier + * @see Callable */ @FunctionalInterface -public interface Fn0 extends Fn1, Supplier { +public interface Fn0 extends Fn1, Supplier, Callable { A apply(); @@ -85,7 +87,12 @@ default Fn0 andThen(Function after) { @Override default A get() { - return apply(UNIT); + return apply(); + } + + @Override + default A call() { + return apply(); } /** From 4a4f177d6607c2232d9f35fcbd16eb07e15999eb Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 16 Nov 2018 16:40:32 -0600 Subject: [PATCH 084/348] Profunctor strength --- CHANGELOG.md | 3 +- .../jnape/palatable/lambda/functions/Fn1.java | 26 +++++++-- .../palatable/lambda/functor/Strong.java | 53 +++++++++++++++++++ .../lambda/functor/builtin/Exchange.java | 9 ++-- .../palatable/lambda/functions/Fn1Test.java | 13 +++++ 5 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functor/Strong.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f1c0c6f7..47f9bc3d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `LiftA3-8`, higher-arity analogs to `LiftA2` - `Alter`, for applying an `Effect` to an input and returning it, presumably altered - `Clamp`, for clamping a value between two bounds -- `Between`, for determining if a value is in a closed interval +- `Between`, for determining if a value is in a closed interval +- `Strong`, profunctor strength ### Deprecated - `AddAll` semigroup, in favor of the monoid that no longer mutates any argument diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 092b5b953..c9fa0ee26 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -1,7 +1,8 @@ package com.jnape.palatable.lambda.functions; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.functor.Strong; import com.jnape.palatable.lambda.monad.Monad; import java.util.function.BiFunction; @@ -18,7 +19,7 @@ * @param The result type */ @FunctionalInterface -public interface Fn1 extends Monad>, Profunctor, Function { +public interface Fn1 extends Monad>, Strong, Function { /** * Invoke this function with the given argument. @@ -116,7 +117,7 @@ default Fn1 discardR(Applicative> appB) { */ @Override default Fn1 diMapL(Function fn) { - return (Fn1) Profunctor.super.diMapL(fn); + return (Fn1) Strong.super.diMapL(fn); } /** @@ -129,7 +130,7 @@ default Fn1 diMapL(Function fn) { */ @Override default Fn1 diMapR(Function fn) { - return (Fn1) Profunctor.super.diMapR(fn); + return (Fn1) Strong.super.diMapR(fn); } /** @@ -146,9 +147,24 @@ default Fn1 diMap(Function lFn, Function the paired value + * @return the strengthened {@link Fn1} + */ + @Override + default Fn1, Tuple2> strengthen() { + return t -> t.fmap(this); + } + + default Fn1> carry() { + return (Fn1>) Strong.super.carry(); + } + @Override default Fn1 contraMap(Function fn) { - return (Fn1) Profunctor.super.contraMap(fn); + return (Fn1) Strong.super.contraMap(fn); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Strong.java b/src/main/java/com/jnape/palatable/lambda/functor/Strong.java new file mode 100644 index 000000000..c31a605b4 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/Strong.java @@ -0,0 +1,53 @@ +package com.jnape.palatable.lambda.functor; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; + +import java.util.function.Function; + +/** + * "Strong" {@link Profunctor profunctors} are profunctors that can be "strengthened" to preserve the pairing of an + * arbitrary type under dimap (p a b -> p (c, a) (c, b) for any type c). + * + * @param the type of the left parameter + * @param the type of the left parameter + * @param the unification parameter + * @see com.jnape.palatable.lambda.functions.Fn1 + */ +public interface Strong extends Profunctor { + + /** + * Pair some type C to this profunctor's carrier types. + * + * @param the paired type + * @return the strengthened profunctor + */ + Strong, Tuple2, S> strengthen(); + + /** + * Pair the covariantly-positioned carrier type with the contravariantly-positioned carrier type. This can be + * thought of as "carrying" or "inspecting" the left parameter. + * + * @return the profunctor with the first parameter carried + */ + default Strong, S> carry() { + return this.strengthen().contraMap(Tuple2::fill); + } + + @Override + Strong diMap(Function lFn, Function rFn); + + @Override + default Strong diMapL(Function fn) { + return (Strong) Profunctor.super.diMapL(fn); + } + + @Override + default Strong diMapR(Function fn) { + return (Strong) Profunctor.super.diMapR(fn); + } + + @Override + default Strong contraMap(Function fn) { + return (Strong) Profunctor.super.contraMap(fn); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java index 1a9439d6b..6a317784c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java @@ -37,20 +37,17 @@ public Exchange diMap(Function lFn, } @Override - @SuppressWarnings("unchecked") public Exchange diMapL(Function fn) { - return (Exchange) Profunctor.super.diMapL(fn); + return (Exchange) Profunctor.super.diMapL(fn); } @Override - @SuppressWarnings("unchecked") public Exchange diMapR(Function fn) { - return (Exchange) Profunctor.super.diMapR(fn); + return (Exchange) Profunctor.super.diMapR(fn); } @Override - @SuppressWarnings("unchecked") public Exchange contraMap(Function fn) { - return (Exchange) Profunctor.super.contraMap(fn); + return (Exchange) Profunctor.super.contraMap(fn); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index b769d67d8..bd3237f2c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -12,6 +12,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; @@ -50,4 +51,16 @@ public void widen() { Fn1 addOne = x -> x + 1; assertEquals(just(4), reduceLeft(addOne.widen().toBiFunction(), asList(1, 2, 3))); } + + @Test + public void strengthen() { + Fn1 add1 = x -> x + 1; + assertEquals(tuple("a", 2), add1.strengthen().apply(tuple("a", 1))); + } + + @Test + public void carry() { + Fn1 add1 = x -> x + 1; + assertEquals(tuple(1, 2), add1.carry().apply(1)); + } } From 794b3cebf48e332ef65d1170bde04937654da1c9 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 18 Nov 2018 18:45:03 -0600 Subject: [PATCH 085/348] Javadocs --- .../lambda/adt/coproduct/CoProduct2.java | 5 +++-- .../lambda/adt/coproduct/CoProduct3.java | 7 ++++--- .../lambda/adt/coproduct/CoProduct4.java | 9 +++++---- .../lambda/adt/coproduct/CoProduct5.java | 11 ++++++----- .../lambda/adt/coproduct/CoProduct6.java | 13 +++++++------ .../lambda/adt/coproduct/CoProduct7.java | 15 ++++++++------- .../lambda/adt/coproduct/CoProduct8.java | 17 +++++++++-------- .../jnape/palatable/lambda/adt/hmap/Schema.java | 9 +++++++++ 8 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java index 6c2c43ee8..5ad1a9908 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java @@ -20,8 +20,9 @@ *

* Learn more about Coproducts. * - * @param the first possible type - * @param the second possible type + * @param the first possible type + * @param the second possible type + * @param the recursive type of this coproduct (used for embedding) * @see Choice2 * @see Either */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java index 967e950e2..23a97ac9c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java @@ -15,9 +15,10 @@ /** * A generalization of the coproduct of three types. * - * @param the first possible type - * @param the second possible type - * @param the third possible type + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the recursive type of this coproduct (used for embedding) * @see CoProduct2 */ @FunctionalInterface diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java index cc4f47b57..2ec2e113d 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java @@ -15,10 +15,11 @@ /** * A generalization of the coproduct of four types. * - * @param the first possible type - * @param the second possible type - * @param the third possible type - * @param the fourth possible type + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the fourth possible type + * @param the recursive type of this coproduct (used for embedding) * @see CoProduct2 */ @FunctionalInterface diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java index aa64d58c0..b90aab2f5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java @@ -15,11 +15,12 @@ /** * A generalization of the coproduct of five types. * - * @param the first possible type - * @param the second possible type - * @param the third possible type - * @param the fourth possible type - * @param the fifth possible type + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the fourth possible type + * @param the fifth possible type + * @param the recursive type of this coproduct (used for embedding) * @see CoProduct2 */ @FunctionalInterface diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java index 2ff159c7b..a3aa40163 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java @@ -16,12 +16,13 @@ /** * A generalization of the coproduct of six types. * - * @param the first possible type - * @param the second possible type - * @param the third possible type - * @param the fourth possible type - * @param the fifth possible type - * @param the sixth possible type + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the fourth possible type + * @param the fifth possible type + * @param the sixth possible type + * @param the recursive type of this coproduct (used for embedding) * @see CoProduct2 */ @FunctionalInterface diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java index 6c8444204..18086211c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java @@ -16,13 +16,14 @@ /** * A generalization of the coproduct of seven types. * - * @param the first possible type - * @param the second possible type - * @param the third possible type - * @param the fourth possible type - * @param the fifth possible type - * @param the sixth possible type - * @param the seventh possible type + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the fourth possible type + * @param the fifth possible type + * @param the sixth possible type + * @param the seventh possible type + * @param the recursive type of this coproduct (used for embedding) * @see CoProduct2 */ @FunctionalInterface diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java index a94ab4586..776f067e8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java @@ -16,14 +16,15 @@ /** * A generalization of the coproduct of eight types. * - * @param the first possible type - * @param the second possible type - * @param the third possible type - * @param the fourth possible type - * @param the fifth possible type - * @param the sixth possible type - * @param the seventh possible type - * @param the eighth possible type + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the fourth possible type + * @param the fifth possible type + * @param the sixth possible type + * @param the seventh possible type + * @param the eighth possible type + * @param the recursive type of this coproduct (used for embedding) * @see CoProduct2 */ @FunctionalInterface 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 index 52e4b0903..a7e3eb371 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java @@ -17,6 +17,14 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.lens.lenses.HMapLens.valueAt; +/** + * A lens that focuses on the {@link HList heterogeneous list} of values pointed at by one or more + * {@link TypeSafeKey typesafe keys} that must all exist in the same {@link HMap} to be collectively extracted. Note + * that if any of the keys is absent in the map, the result will be {@link Maybe#nothing()}. + * + * @param the {@link HList} of values to focus on + * @see TypeSafeKey + */ public interface Schema> extends Lens.Simple> { @SuppressWarnings("unchecked") @@ -28,6 +36,7 @@ default > Schema add(TypeSafeKe ::apply; } + @SuppressWarnings("unchecked") static Schema> schema(TypeSafeKey key) { return valueAt(key) .mapA(ma -> ma.fmap(HList::singletonHList)) From 1348fc7a68ffb504c76ecb4d40a534df919c125b Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 29 Nov 2018 00:43:41 -0600 Subject: [PATCH 086/348] IO monad arrives --- CHANGELOG.md | 5 +- .../palatable/lambda/functions/Effect.java | 10 +- .../jnape/palatable/lambda/functions/Fn0.java | 8 +- .../jnape/palatable/lambda/functions/IO.java | 118 ++++++++++++++++++ .../lambda/functions/builtin/fn2/Alter.java | 15 +-- .../palatable/lambda/functions/IOTest.java | 32 +++++ .../functions/builtin/fn2/AlterTest.java | 2 +- .../java/testsupport/EqualityAwareIO.java | 64 ++++++++++ 8 files changed, 236 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/IO.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/IOTest.java create mode 100644 src/test/java/testsupport/EqualityAwareIO.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 47f9bc3d0..079c6b54f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - ***Breaking Change***: `Effect#accept()` is now the required method to implement in the functional interface - ***Breaking Change***: `Fn0#apply()` is now the required method to implement in the functional interface - ***Breaking Change***: `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` take the right-hand side first for more intuitive partial application +- ***Breaking Change***: `Effect` now returns an `IO` +- ***Breaking Change***: `Alter` now returns an `IO` - `RightAny` overload returns `Monoid` - monoids now all fold with respect to `foldMap` - monoid folding now implicitly starts with the identity, regardless of iterable population @@ -29,7 +31,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Alter`, for applying an `Effect` to an input and returning it, presumably altered - `Clamp`, for clamping a value between two bounds - `Between`, for determining if a value is in a closed interval -- `Strong`, profunctor strength +- `Strong`, profunctor strength +- `IO` monad ### Deprecated - `AddAll` semigroup, in favor of the monoid that no longer mutates any argument diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index f9adebe97..8a341d9a3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -6,7 +6,8 @@ import java.util.function.Consumer; import java.util.function.Function; -import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; +import static com.jnape.palatable.lambda.functions.IO.io; /** * A function returning "no result", and therefore only useful as a side-effect. @@ -16,12 +17,11 @@ * @see Consumer */ @FunctionalInterface -public interface Effect extends Fn1, Consumer { +public interface Effect extends Fn1>, Consumer { @Override - default Unit apply(A a) { - accept(a); - return UNIT; + default IO apply(A a) { + return io(fn0(() -> accept(a))); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index 023f531c3..84eb3e4a8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -9,7 +9,7 @@ import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.Effect.effect; +import static com.jnape.palatable.lambda.functions.IO.io; /** * A function taking "no arguments", implemented as an {@link Fn1}<{@link Unit}, A>. @@ -120,11 +120,11 @@ static Fn0 fn0(Fn0 fn) { /** * Static factory method for adapting a {@link Runnable} to an {@link Fn0}<{@link Unit}>. * - * @param fn the {@link Runnable} + * @param runnable the {@link Runnable} * @return the {@link Fn0} */ - static Fn0 fn0(Runnable fn) { - return effect(fn).thunk(UNIT); + static Fn0 fn0(Runnable runnable) { + return io(runnable)::unsafePerformIO; } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/IO.java b/src/main/java/com/jnape/palatable/lambda/functions/IO.java new file mode 100644 index 000000000..8e05dfcaf --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/IO.java @@ -0,0 +1,118 @@ +package com.jnape.palatable.lambda.functions; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; + +/** + * A {@link Monad} representing some effectful computation to be performed. + * + * @param the result type + */ +public interface IO extends Monad> { + + /** + * Run the effect represented by this {@link IO} instance + * + * @return the result of the effect + */ + A unsafePerformIO(); + + /** + * {@inheritDoc} + */ + @Override + default IO flatMap(Function>> f) { + return () -> f.apply(unsafePerformIO()).>coerce().unsafePerformIO(); + } + + /** + * {@inheritDoc} + */ + @Override + default IO pure(B b) { + return () -> b; + } + + /** + * {@inheritDoc} + */ + @Override + default IO fmap(Function fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default IO zip(Applicative, IO> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default IO discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default IO discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } + + /** + * Static factory method for coercing a lambda to an {@link IO}. + * + * @param io the lambda to coerce + * @param the result type + * @return the {@link IO} + */ + static IO io(IO io) { + return io; + } + + /** + * Static factory method for creating an {@link IO} that just returns a when performed. + * + * @param a the result + * @param the result type + * @return the {@link IO} + */ + static IO io(A a) { + return io(() -> a); + } + + /** + * Static factory method for creating an {@link IO} that runs runnable and returns {@link Unit}. + * + * @param runnable the {@link Runnable} + * @return the {@link IO} + */ + static IO io(Runnable runnable) { + return io(() -> { + runnable.run(); + return UNIT; + }); + } + + /** + * Static factory method for creating an {@link IO} from an {@link Fn1}<{@link Unit}, A>. + * + * @param fn1 the {@link Fn1} + * @param the result type + * @return the {@link IO} + */ + static IO io(Fn1 fn1) { + return io(() -> fn1.apply(UNIT)); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java index 5b122c5ff..f51050eae 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -3,16 +3,17 @@ import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.IO; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** - * Given an {@link Effect}<A> and some A, perform the effect on the A and - * return it. + * Given an {@link Effect}<A> and some A, produce an {@link IO} that, when run, performs + * the effect on A and returns it. * * @param the input and output */ -public final class Alter implements Fn2, A, A> { +public final class Alter implements Fn2, A, IO> { private static final Alter INSTANCE = new Alter(); @@ -20,8 +21,8 @@ private Alter() { } @Override - public A apply(Effect effect, A a) { - return effect.fmap(constantly(a)).apply(a); + public IO apply(Effect effect, A a) { + return effect.fmap(io -> io.fmap(constantly(a))).apply(a); } @SuppressWarnings("unchecked") @@ -29,11 +30,11 @@ public static Alter alter() { return INSTANCE; } - public static Fn1 alter(Effect effect) { + public static Fn1> alter(Effect effect) { return Alter.alter().apply(effect); } - public static A alter(Effect effect, A a) { + public static IO alter(Effect effect, A a) { return Alter.alter(effect).apply(a); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java b/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java new file mode 100644 index 000000000..e9038fa6f --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java @@ -0,0 +1,32 @@ +package com.jnape.palatable.lambda.functions; + +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.EqualityAwareIO; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; +import static com.jnape.palatable.lambda.functions.IO.io; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class IOTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public IO testSubject() { + return new EqualityAwareIO<>(io(1)); + } + + @Test + public void staticFactoryMethods() { + assertEquals((Integer) 1, io(1).unsafePerformIO()); + assertEquals((Integer) 1, io(() -> 1).unsafePerformIO()); + assertEquals((Integer) 1, io(fn0(() -> 1)).unsafePerformIO()); + assertEquals(UNIT, io(() -> {}).unsafePerformIO()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java index 8a8031f61..73e11e800 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java @@ -14,7 +14,7 @@ public class AlterTest { @Test public void altersInput() { ArrayList input = new ArrayList<>(); - assertSame(input, alter(xs -> xs.add("foo"), input)); + assertSame(input, alter(xs -> xs.add("foo"), input).unsafePerformIO()); assertEquals(singletonList("foo"), input); } } \ No newline at end of file diff --git a/src/test/java/testsupport/EqualityAwareIO.java b/src/test/java/testsupport/EqualityAwareIO.java new file mode 100644 index 000000000..822cfebf7 --- /dev/null +++ b/src/test/java/testsupport/EqualityAwareIO.java @@ -0,0 +1,64 @@ +package testsupport; + +import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; + +import static java.util.Objects.hash; + +public final class EqualityAwareIO implements IO { + private final IO io; + + public EqualityAwareIO(IO io) { + this.io = io; + } + + @Override + public A unsafePerformIO() { + return io.unsafePerformIO(); + } + + @Override + public EqualityAwareIO flatMap(Function>> f) { + return new EqualityAwareIO<>(io.flatMap(f)); + } + + @Override + public EqualityAwareIO fmap(Function f) { + return new EqualityAwareIO<>(io.fmap(f)); + } + + @Override + public EqualityAwareIO zip(Applicative, IO> appFn) { + return new EqualityAwareIO<>(io.zip(appFn)); + } + + @Override + public EqualityAwareIO pure(B b) { + return new EqualityAwareIO<>(io.pure(b)); + } + + + @Override + public EqualityAwareIO discardL(Applicative> appB) { + return new EqualityAwareIO<>(io.discardL(appB)); + } + + @Override + public EqualityAwareIO discardR(Applicative> appB) { + return new EqualityAwareIO<>(io.discardR(appB)); + } + + @Override + @SuppressWarnings("unchecked") + public boolean equals(Object other) { + return other instanceof IO && ((IO) other).unsafePerformIO().equals(unsafePerformIO()); + } + + @Override + public int hashCode() { + return hash(io); + } +} From 14cb27f248282ec7cfc0dc92a504fc775ee4fd0d Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 2 Dec 2018 17:04:34 -0600 Subject: [PATCH 087/348] CheckedRunnable is an IO --- CHANGELOG.md | 1 + .../specialized/checked/CheckedRunnable.java | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 079c6b54f..86026c917 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Either#diverge` returns a `Choice3` - `Maybe` is now a `CoProduct2` of `Unit` and `A` - `Fn0` now additionally implements `Callable` +- `CheckedRunnable` is an `IO` ### Added - `Predicate#predicate` static factory method diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java index 2552c746e..7eb794917 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functions.specialized.checked; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.IO; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; @@ -13,7 +14,14 @@ * @see CheckedFn1 */ @FunctionalInterface -public interface CheckedRunnable extends Runnable { +public interface CheckedRunnable extends Runnable, IO { + + /** + * A version of {@link Runnable#run()} that can throw checked exceptions. + * + * @throws T any exception that can be thrown by this method + */ + void checkedRun() throws T; @Override default void run() { @@ -24,12 +32,11 @@ default void run() { } } - /** - * A version of {@link Runnable#run()} that can throw checked exceptions. - * - * @throws T any exception that can be thrown by this method - */ - void checkedRun() throws T; + @Override + default Unit unsafePerformIO() { + run(); + return UNIT; + } /** * Convert this {@link CheckedRunnable} to a {@link CheckedSupplier} that returns {@link Unit}. From efefe5aca45c8befa026561439ecd7402e416d23 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 2 Dec 2018 17:09:59 -0600 Subject: [PATCH 088/348] RunAll semigroup and monoid for IO --- CHANGELOG.md | 1 + .../lambda/monoid/builtin/RunAll.java | 47 +++++++++++++++++++ .../lambda/semigroup/builtin/RunAll.java | 42 +++++++++++++++++ .../lambda/monoid/builtin/RunAllTest.java | 18 +++++++ .../lambda/semigroup/builtin/RunAllTest.java | 17 +++++++ 5 files changed, 125 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java create mode 100644 src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 86026c917..d02db6c43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Between`, for determining if a value is in a closed interval - `Strong`, profunctor strength - `IO` monad +- `RunAll` semigroup and monoid instance for `IO` ### Deprecated - `AddAll` semigroup, in favor of the monoid that no longer mutates any argument diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java new file mode 100644 index 000000000..8e3c0d869 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java @@ -0,0 +1,47 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; +import com.jnape.palatable.lambda.monoid.Monoid; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.monoid.Monoid.monoid; + +/** + * Run {@link IO} operations, aggregating their results in terms of the provided {@link Monoid}. + * + * @param the {@link IO} result + * @see com.jnape.palatable.lambda.semigroup.builtin.RunAll + */ +public final class RunAll implements MonoidFactory, IO> { + + private static final RunAll INSTANCE = new RunAll(); + + private RunAll() { + } + + @Override + public Monoid> apply(Monoid monoid) { + Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.RunAll.runAll(monoid); + return monoid(semigroup, io(monoid.identity())); + } + + @SuppressWarnings("unchecked") + public static RunAll runAll() { + return INSTANCE; + } + + public static Monoid> runAll(Monoid monoid) { + return RunAll.runAll().apply(monoid); + } + + public static Fn1, IO> runAll(Monoid monoid, IO x) { + return runAll(monoid).apply(x); + } + + public static IO runAll(Monoid monoid, IO x, IO y) { + return runAll(monoid, x).apply(y); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java new file mode 100644 index 000000000..5ae09b8ac --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java @@ -0,0 +1,42 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +/** + * Run {@link IO} operations, aggregating their results in terms of the provided {@link Semigroup}. + * + * @param the {@link IO} result + * @see com.jnape.palatable.lambda.monoid.builtin.RunAll + */ +public final class RunAll implements SemigroupFactory, IO> { + + private static final RunAll INSTANCE = new RunAll(); + + private RunAll() { + } + + @Override + public Semigroup> apply(Semigroup semigroup) { + return (ioX, ioY) -> ioY.zip(ioX.fmap(semigroup)); + } + + @SuppressWarnings("unchecked") + public static RunAll runAll() { + return INSTANCE; + } + + public static Semigroup> runAll(Semigroup semigroup) { + return RunAll.runAll().apply(semigroup); + } + + public static Fn1, IO> runAll(Semigroup semigroup, IO ioX) { + return runAll(semigroup).apply(ioX); + } + + public static IO runAll(Semigroup semigroup, IO ioX, IO ioY) { + return runAll(semigroup, ioX).apply(ioY); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java new file mode 100644 index 000000000..782ee334f --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java @@ -0,0 +1,18 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.monoid.Monoid; +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.monoid.builtin.RunAll.runAll; +import static org.junit.Assert.assertEquals; + +public class RunAllTest { + + @Test + public void monoid() { + Monoid add = Monoid.monoid((x, y) -> x + y, 0); + assertEquals((Integer) 3, runAll(add).apply(io(1), io(2)).unsafePerformIO()); + assertEquals((Integer) 0, runAll(add).identity().unsafePerformIO()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java new file mode 100644 index 000000000..c8840da69 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java @@ -0,0 +1,17 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.semigroup.Semigroup; +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.semigroup.builtin.RunAll.runAll; +import static org.junit.Assert.assertEquals; + +public class RunAllTest { + + @Test + public void semigroup() { + Semigroup add = (x, y) -> x + y; + assertEquals((Integer) 3, runAll(add).apply(io(1), io(2)).unsafePerformIO()); + } +} \ No newline at end of file From 08cc0f2dca91addc6f6fd03e23255070bde0aa68 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 2 Dec 2018 18:08:56 -0600 Subject: [PATCH 089/348] Ritual sacrifice to the javadoc gods --- CHANGELOG.md | 1 - src/main/java/com/jnape/palatable/lambda/functor/Strong.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d02db6c43..e04438485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - ***Breaking Change***: `Fn0#apply()` is now the required method to implement in the functional interface - ***Breaking Change***: `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` take the right-hand side first for more intuitive partial application - ***Breaking Change***: `Effect` now returns an `IO` -- ***Breaking Change***: `Alter` now returns an `IO` - `RightAny` overload returns `Monoid` - monoids now all fold with respect to `foldMap` - monoid folding now implicitly starts with the identity, regardless of iterable population diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Strong.java b/src/main/java/com/jnape/palatable/lambda/functor/Strong.java index c31a605b4..c6b4929c2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Strong.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Strong.java @@ -6,7 +6,7 @@ /** * "Strong" {@link Profunctor profunctors} are profunctors that can be "strengthened" to preserve the pairing of an - * arbitrary type under dimap (p a b -> p (c, a) (c, b) for any type c). + * arbitrary type under dimap (p a b -> p (c, a) (c, b) for any type c). * * @param the type of the left parameter * @param the type of the left parameter From 68029d2cabb46db831d1a53e27c125bf6ab5de44 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 8 Dec 2018 17:19:06 -0600 Subject: [PATCH 090/348] [maven-release-plugin] prepare release lambda-3.2.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 94275b818..a117dcaf0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.1.1-SNAPSHOT + 3.2.0 jar Lambda From 82c21757ec953dfaf0d2dff1af750af51ca128b0 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 8 Dec 2018 17:19:13 -0600 Subject: [PATCH 091/348] [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 a117dcaf0..977cbab29 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.2.0 + 3.2.1-SNAPSHOT jar Lambda From 84e3f6c5ecd59a69b6d51461acb5b30b978f2563 Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Sun, 9 Dec 2018 12:35:54 -0600 Subject: [PATCH 092/348] Added MapMerge (#34) - Given a Map supplier and a Semigroup over B get a Monoid> --- .../lambda/monoid/builtin/MergeMaps.java | 55 +++++++++++++++++++ .../lambda/monoid/builtin/MergeMapsTest.java | 43 +++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeMapsTest.java diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java new file mode 100644 index 000000000..275f2af3f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java @@ -0,0 +1,55 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.BiMonoidFactory; +import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; +import com.jnape.palatable.lambda.monoid.Monoid; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Supplier; + +/** + * A {@link Monoid} instance formed by {@link Map#merge(K, V, BiFunction)} and a semigroup over V. + * Combines together multiple maps using the provided semigroup for key collisions. + * + * @param The key parameter type of the Map + * @param The value parameter type of the Map + * @see Monoid + * @see java.util.Map + */ +public class MergeMaps implements BiMonoidFactory>, Semigroup, Map> { + private MergeMaps() { + } + + @Override + public Monoid> apply(Supplier> mSupplier, Semigroup semigroup) { + return Monoid.>monoid((x, y) -> { + Map copy = mSupplier.get(); + copy.putAll(x); + y.forEach((k, v) -> copy.merge(k, v, semigroup.toBiFunction())); + return copy; + }, mSupplier); + } + + public static MergeMaps mergeMaps() { + return new MergeMaps<>(); + } + + public static MonoidFactory, Map> mergeMaps(Supplier> mSupplier) { + return MergeMaps.mergeMaps().apply(mSupplier); + } + + public static Monoid> mergeMaps(Supplier> mSupplier, Semigroup semigroup) { + return mergeMaps(mSupplier).apply(semigroup); + } + + public static Fn1, Map> mergeMaps(Supplier> mSupplier, Semigroup semigroup, Map x) { + return mergeMaps(mSupplier, semigroup).apply(x); + } + + public static Map mergeMaps(Supplier> mSupplier, Semigroup semigroup, Map x, Map y) { + return mergeMaps(mSupplier, semigroup, x).apply(y); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeMapsTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeMapsTest.java new file mode 100644 index 000000000..be871be21 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeMapsTest.java @@ -0,0 +1,43 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.monoid.Monoid; +import com.jnape.palatable.lambda.semigroup.Semigroup; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap; +import static com.jnape.palatable.lambda.monoid.builtin.MergeMaps.mergeMaps; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class MergeMapsTest { + private static final Semigroup ADD = (x, y) -> x + y; + private Monoid> merge; + + @Before + public void setUp() { + merge = mergeMaps(HashMap::new, ADD); + } + + @Test + public void identity() { + assertTrue(merge.identity().isEmpty()); + } + + @Test + public void monoid() { + assertEquals(singletonMap("foo", 1), merge.apply(emptyMap(), singletonMap("foo", 1))); + assertEquals(singletonMap("foo", 1), merge.apply(singletonMap("foo", 1), emptyMap())); + assertEquals(singletonMap("foo", 2), + merge.apply(singletonMap("foo", 1), singletonMap("foo", 1))); + assertEquals(toMap(HashMap::new, asList(tuple("foo", 1), tuple("bar", 1))), + merge.apply(singletonMap("foo", 1), singletonMap("bar", 1))); + } +} \ No newline at end of file From bd28ff03d9b6c623ffb10fdcba77fad10b2a61bc Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 9 Dec 2018 15:20:48 -0600 Subject: [PATCH 093/348] Housekeeping --- CHANGELOG.md | 7 +++++- README.md | 4 ++-- .../lambda/monoid/builtin/MergeMaps.java | 22 ++++++++++++------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e04438485..82befdab2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ 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 +- `MergeMaps`, a `Monoid` on `Map` formed by `Map#merge` + +## [3.2.0] - 2018-12-08 ### Changed - ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to `functions.builtin.fn2` package - ***Breaking Change***: `Absent` moved to `semigroup.builtin` package @@ -404,7 +408,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.1.0...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-3.2.0...HEAD +[3.2.0]: https://github.com/palatable/lambda/compare/lambda-3.1.0...lambda-3.2.0 [3.1.0]: https://github.com/palatable/lambda/compare/lambda-3.0.3...lambda-3.1.0 [3.0.3]: https://github.com/palatable/lambda/compare/lambda-3.0.2...lambda-3.0.3 [3.0.2]: https://github.com/palatable/lambda/compare/lambda-3.0.1...lambda-3.0.2 diff --git a/README.md b/README.md index 1d2dc60b0..65501c222 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 3.1.0 + 3.2.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '3.1.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '3.2.0' ``` Examples diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java index 275f2af3f..8de8ffdc2 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java @@ -19,7 +19,10 @@ * @see Monoid * @see java.util.Map */ -public class MergeMaps implements BiMonoidFactory>, Semigroup, Map> { +public final class MergeMaps implements BiMonoidFactory>, Semigroup, Map> { + + private static final MergeMaps INSTANCE = new MergeMaps(); + private MergeMaps() { } @@ -33,23 +36,26 @@ public Monoid> apply(Supplier> mSupplier, Semigroup semig }, mSupplier); } - public static MergeMaps mergeMaps() { - return new MergeMaps<>(); + @SuppressWarnings("unchecked") + public static MergeMaps mergeMaps() { + return INSTANCE; } - public static MonoidFactory, Map> mergeMaps(Supplier> mSupplier) { - return MergeMaps.mergeMaps().apply(mSupplier); + public static MonoidFactory, Map> mergeMaps(Supplier> mSupplier) { + return MergeMaps.mergeMaps().apply(mSupplier); } - public static Monoid> mergeMaps(Supplier> mSupplier, Semigroup semigroup) { + public static Monoid> mergeMaps(Supplier> mSupplier, Semigroup semigroup) { return mergeMaps(mSupplier).apply(semigroup); } - public static Fn1, Map> mergeMaps(Supplier> mSupplier, Semigroup semigroup, Map x) { + public static Fn1, Map> mergeMaps(Supplier> mSupplier, Semigroup semigroup, + Map x) { return mergeMaps(mSupplier, semigroup).apply(x); } - public static Map mergeMaps(Supplier> mSupplier, Semigroup semigroup, Map x, Map y) { + public static Map mergeMaps(Supplier> mSupplier, Semigroup semigroup, Map x, + Map y) { return mergeMaps(mSupplier, semigroup, x).apply(y); } } From 13863a6bb16f2282d93c94fd31842772e3c7fd43 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 8 Jan 2019 19:48:45 -0600 Subject: [PATCH 094/348] Moving IO to its own package --- .../java/com/jnape/palatable/lambda/functions/Effect.java | 3 ++- src/main/java/com/jnape/palatable/lambda/functions/Fn0.java | 2 +- .../jnape/palatable/lambda/functions/builtin/fn2/Alter.java | 2 +- .../lambda/functions/specialized/checked/CheckedRunnable.java | 2 +- .../java/com/jnape/palatable/lambda/{functions => io}/IO.java | 3 ++- .../com/jnape/palatable/lambda/monoid/builtin/RunAll.java | 4 ++-- .../com/jnape/palatable/lambda/semigroup/builtin/RunAll.java | 2 +- .../com/jnape/palatable/lambda/{functions => io}/IOTest.java | 4 ++-- .../com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java | 2 +- .../jnape/palatable/lambda/semigroup/builtin/RunAllTest.java | 2 +- src/test/java/testsupport/EqualityAwareIO.java | 2 +- 11 files changed, 15 insertions(+), 13 deletions(-) rename src/main/java/com/jnape/palatable/lambda/{functions => io}/IO.java (96%) rename src/test/java/com/jnape/palatable/lambda/{functions => io}/IOTest.java (90%) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 8a341d9a3..ce3bde608 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -2,12 +2,13 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.io.IO; import java.util.function.Consumer; import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn0.fn0; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; /** * A function returning "no result", and therefore only useful as a side-effect. diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index 84eb3e4a8..74d742cbc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -9,7 +9,7 @@ import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; /** * A function taking "no arguments", implemented as an {@link Fn1}<{@link Unit}, A>. diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java index f51050eae..488de31ce 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java index 7eb794917..358072f93 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.functions.specialized.checked; import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java similarity index 96% rename from src/main/java/com/jnape/palatable/lambda/functions/IO.java rename to src/main/java/com/jnape/palatable/lambda/io/IO.java index 8e05dfcaf..cac71ebd9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -1,6 +1,7 @@ -package com.jnape.palatable.lambda.functions; +package com.jnape.palatable.lambda.io; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java index 8e3c0d869..871deebb1 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java @@ -1,12 +1,12 @@ package com.jnape.palatable.lambda.monoid.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; import com.jnape.palatable.lambda.monoid.Monoid; import com.jnape.palatable.lambda.semigroup.Semigroup; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monoid.Monoid.monoid; /** diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java index 5ae09b8ac..b46ff9612 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; import com.jnape.palatable.lambda.semigroup.Semigroup; diff --git a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java similarity index 90% rename from src/test/java/com/jnape/palatable/lambda/functions/IOTest.java rename to src/test/java/com/jnape/palatable/lambda/io/IOTest.java index e9038fa6f..3ebe09425 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.functions; +package com.jnape.palatable.lambda.io; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; @@ -11,7 +11,7 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.Fn0.fn0; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static org.junit.Assert.assertEquals; @RunWith(Traits.class) diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java index 782ee334f..c0e9f6d17 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.monoid.Monoid; import org.junit.Test; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monoid.builtin.RunAll.runAll; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java index c8840da69..329fe8429 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.semigroup.Semigroup; import org.junit.Test; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.semigroup.builtin.RunAll.runAll; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/testsupport/EqualityAwareIO.java b/src/test/java/testsupport/EqualityAwareIO.java index 822cfebf7..ac1d56f14 100644 --- a/src/test/java/testsupport/EqualityAwareIO.java +++ b/src/test/java/testsupport/EqualityAwareIO.java @@ -1,6 +1,6 @@ package testsupport; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; From fcf9ff8cafd7cc2c16693413b5a4b1aac5e07799 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 12 Jan 2019 13:29:30 -0600 Subject: [PATCH 095/348] Fixing bug where Effect is nullified under certain compositions Co-authored-by: Alexander Bandukwala <7h3kk1d@gmail.com> --- CHANGELOG.md | 3 ++ .../palatable/lambda/functions/Effect.java | 8 +++--- .../lambda/functions/EffectTest.java | 28 +++++++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82befdab2..48486e807 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `MergeMaps`, a `Monoid` on `Map` formed by `Map#merge` +### Fixed +- issue where certain ways to compose `Effect`s unintentionally nullified the effect + ## [3.2.0] - 2018-12-08 ### Changed - ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to `functions.builtin.fn2` package diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index ce3bde608..4712299b7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -27,22 +27,22 @@ default IO apply(A a) { @Override default Effect diMapL(Function fn) { - return Fn1.super.diMapL(fn)::apply; + return effect(z -> Fn1.super.diMapL(fn).apply(z).unsafePerformIO()); } @Override default Effect contraMap(Function fn) { - return Fn1.super.contraMap(fn)::apply; + return effect(z -> Fn1.super.contraMap(fn).apply(z).unsafePerformIO()); } @Override default Effect compose(Function before) { - return Fn1.super.compose(before)::apply; + return effect(z -> Fn1.super.compose(before).apply(z).unsafePerformIO()); } @Override default Effect discardR(Applicative> appB) { - return Fn1.super.discardR(appB)::apply; + return effect(a -> Fn1.super.discardR(appB).apply(a).unsafePerformIO()); } @Override diff --git a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java index 1b22b349b..dd38e6add 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java @@ -2,21 +2,33 @@ import org.junit.Test; -import java.util.function.Consumer; +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.specialized.Noop.noop; +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; public class EffectTest { @Test - @SuppressWarnings("unused") public void covariantReturns() { - Effect effect = noop(); - Effect diMapL = effect.diMapL(constantly("1")); - Effect contraMap = effect.contraMap(constantly("1")); - Effect compose = effect.compose(constantly("1")); + List results = new ArrayList<>(); + + Effect effect = results::add; + Effect diMapL = effect.diMapL(Object::toString); + Effect contraMap = effect.contraMap(Object::toString); + Effect compose = effect.compose(Object::toString); Effect stringEffect = effect.discardR(constantly("1")); - Effect andThen = effect.andThen((Consumer) noop()); + Effect andThen = effect.andThen(effect); + + effect.accept("1"); + diMapL.accept("2"); + contraMap.accept("3"); + compose.accept("4"); + stringEffect.accept("5"); + andThen.accept("6"); + + assertEquals(asList("1", "2", "3", "4", "5", "6", "6"), results); } } \ No newline at end of file From ff424b036bb8860a7606f42ffa313d7c4d498639 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Jan 2019 17:45:41 -0600 Subject: [PATCH 096/348] CheckedEffect/CheckedSupplier are CheckedFn1, now with more overrides --- CHANGELOG.md | 5 +- .../specialized/checked/CheckedEffect.java | 69 +++++++++- .../specialized/checked/CheckedFn1.java | 122 ++++++++++++++++++ .../specialized/checked/CheckedSupplier.java | 109 ++++++++++++++-- .../checked/CheckedEffectTest.java | 34 +++++ .../specialized/checked/CheckedFn1Test.java | 47 +++++++ .../checked/CheckedSupplierTest.java | 42 ++++++ 7 files changed, 416 insertions(+), 12 deletions(-) create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 48486e807..5fc01f1a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Added -- `MergeMaps`, a `Monoid` on `Map` formed by `Map#merge` +- `MergeMaps`, a `Monoid` on `Map` formed by `Map#merge` +- `CheckedEffect` is now a `CheckedFn1` +- `CheckedSupplier` is now a `CheckedFn1` +- `CheckedFn1` now overrides all possible methods with covariant return type ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java index 0197295ee..7e1a42fa5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java @@ -1,8 +1,16 @@ package com.jnape.palatable.lambda.functions.specialized.checked; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functions.Effect; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.io.IO; + +import java.util.function.Consumer; +import java.util.function.Function; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; +import static com.jnape.palatable.lambda.io.IO.io; /** * Specialized {@link Effect} that can throw any {@link Throwable}. @@ -14,8 +22,11 @@ * @see Effect */ @FunctionalInterface -public interface CheckedEffect extends Effect { +public interface CheckedEffect extends Effect, CheckedFn1> { + /** + * {@inheritDoc} + */ @Override default void accept(A a) { try { @@ -25,6 +36,62 @@ default void accept(A a) { } } + /** + * {@inheritDoc} + */ + @Override + default IO apply(A a) { + return io(() -> accept(a)); + } + + /** + * {@inheritDoc} + */ + @Override + default IO checkedApply(A a) throws T { + return apply(a); + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedEffect diMapL(Function fn) { + return Effect.super.diMapL(fn)::accept; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedEffect contraMap(Function fn) { + return Effect.super.contraMap(fn)::accept; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedEffect compose(Function before) { + return Effect.super.compose(before)::accept; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedEffect discardR(Applicative> appB) { + return Effect.super.discardR(appB)::accept; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedEffect andThen(Consumer after) { + return Effect.super.andThen(after)::accept; + } + /** * A version of {@link Effect#accept} that can throw checked exceptions. * diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java index e35dd70da..4b5bd93a7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java @@ -1,6 +1,12 @@ package com.jnape.palatable.lambda.functions.specialized.checked; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; @@ -17,6 +23,9 @@ @FunctionalInterface public interface CheckedFn1 extends Fn1 { + /** + * {@inheritDoc} + */ @Override default B apply(A a) { try { @@ -26,6 +35,119 @@ default B apply(A a) { } } + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 fmap(Function f) { + return Fn1.super.fmap(f)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 flatMap(Function>> f) { + return Fn1.super.flatMap(f).>coerce()::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 discardL(Applicative> appB) { + return Fn1.super.discardL(appB)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 discardR(Applicative> appB) { + return Fn1.super.discardR(appB)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 zip(Applicative, Fn1> appFn) { + return Fn1.super.zip(appFn)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 zip(Fn2 appFn) { + return Fn1.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 diMapL(Function fn) { + return Fn1.super.diMapL(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 diMapR(Function fn) { + return Fn1.super.diMapR(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 diMap(Function lFn, + Function rFn) { + return Fn1.super.diMap(lFn, rFn)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1, Tuple2> strengthen() { + return Fn1.super.strengthen()::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1> carry() { + return Fn1.super.carry()::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 contraMap(Function fn) { + return Fn1.super.contraMap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 compose(Function before) { + return Fn1.super.compose(before)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedFn1 andThen(Function after) { + return Fn1.super.andThen(after)::apply; + } + /** * A version of {@link Fn1#apply} that can throw checked exceptions. * diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java index b32f1e4b8..627da8c91 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java @@ -1,7 +1,16 @@ package com.jnape.palatable.lambda.functions.specialized.checked; +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; import java.util.function.Supplier; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; /** @@ -13,16 +22,7 @@ * @see CheckedRunnable */ @FunctionalInterface -public interface CheckedSupplier extends Supplier { - - @Override - default A get() { - try { - return checkedGet(); - } catch (Throwable t) { - throw throwChecked(t); - } - } +public interface CheckedSupplier extends Supplier, CheckedFn1 { /** * A version of {@link Supplier#get()} that can throw checked exceptions. @@ -41,6 +41,95 @@ default CheckedRunnable toRunnable() { return this::get; } + @Override + default A checkedApply(Unit unit) throws T { + return checkedGet(); + } + + /** + * {@inheritDoc} + */ + @Override + default A get() { + try { + return checkedGet(); + } catch (Throwable t) { + throw throwChecked(t); + } + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier fmap(Function f) { + return CheckedFn1.super.fmap(f).thunk(UNIT)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier flatMap(Function>> f) { + return CheckedFn1.super.flatMap(f).thunk(UNIT)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier discardL(Applicative> appB) { + return CheckedFn1.super.discardL(appB).thunk(UNIT)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier discardR(Applicative> appB) { + return CheckedFn1.super.discardR(appB).thunk(UNIT)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier zip(Applicative, Fn1> appFn) { + return CheckedFn1.super.zip(appFn).thunk(UNIT)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier zip(Fn2 appFn) { + return CheckedFn1.super.zip(appFn).thunk(UNIT)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier diMapR(Function fn) { + return CheckedFn1.super.diMapR(fn).thunk(UNIT)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier> carry() { + return CheckedFn1.super.carry().thunk(UNIT)::apply; + } + + /** + * {@inheritDoc} + */ + @Override + default CheckedSupplier andThen(Function after) { + return CheckedFn1.super.andThen(after).thunk(UNIT)::apply; + } + /** * Convenience static factory method for constructing a {@link CheckedSupplier} without an explicit cast or type * attribution at the call site. diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java new file mode 100644 index 000000000..8472dc067 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java @@ -0,0 +1,34 @@ +package com.jnape.palatable.lambda.functions.specialized.checked; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +public class CheckedEffectTest { + + @Test + public void assignment() { + List results = new ArrayList<>(); + + CheckedEffect effect = results::add; + CheckedEffect diMapL = effect.diMapL(Object::toString); + CheckedEffect contraMap = effect.contraMap(Object::toString); + CheckedEffect compose = effect.compose(Object::toString); + CheckedEffect stringEffect = effect.discardR(constantly("1")); + CheckedEffect andThen = effect.andThen(effect); + + effect.accept("1"); + diMapL.accept("2"); + contraMap.accept("3"); + compose.accept("4"); + stringEffect.accept("5"); + andThen.accept("6"); + + assertEquals(asList("1", "2", "3", "4", "5", "6", "6"), results); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java new file mode 100644 index 000000000..a8818d684 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java @@ -0,0 +1,47 @@ +package com.jnape.palatable.lambda.functions.specialized.checked; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static org.junit.Assert.assertEquals; + +public class CheckedFn1Test { + + @Test + public void assignment() { + CheckedFn1 parseInt = Integer::parseInt; + CheckedFn1 fmap = parseInt.fmap(Object::toString); + CheckedFn1 flatMap = parseInt.flatMap(i -> constantly(i + "")); + CheckedFn1 discardL = parseInt.discardL(constantly("0")); + CheckedFn1 discardR = parseInt.discardR(constantly("0")); + CheckedFn1 zipApp = parseInt.zip(constantly(id())); + CheckedFn1 zipF = parseInt.zip(constantly()); + CheckedFn1 diMapL = parseInt.diMapL(id()); + CheckedFn1 diMapR = parseInt.diMapR(id()); + CheckedFn1 diMap = parseInt.diMap(id(), id()); + CheckedFn1, Tuple2> strengthen = parseInt.strengthen(); + CheckedFn1> carry = parseInt.carry(); + CheckedFn1 contraMap = parseInt.contraMap(id()); + CheckedFn1 compose = parseInt.compose(id()); + CheckedFn1 andThen = parseInt.andThen(id()); + + assertEquals((Integer) 1, parseInt.apply("1")); + assertEquals("1", fmap.apply("1")); + assertEquals("1", flatMap.apply("1")); + assertEquals("0", discardL.apply("1")); + assertEquals((Integer) 1, discardR.apply("1")); + assertEquals((Integer) 1, zipApp.apply("1")); + assertEquals("1", zipF.apply("1")); + assertEquals((Integer) 1, diMapL.apply("1")); + assertEquals((Integer) 1, diMapR.apply("1")); + assertEquals((Integer) 1, diMap.apply("1")); + assertEquals(tuple("foo", 1), strengthen.apply(tuple("foo", "1"))); + assertEquals(tuple("1", 1), carry.apply("1")); + assertEquals((Integer) 1, contraMap.apply("1")); + assertEquals((Integer) 1, compose.apply("1")); + assertEquals((Integer) 1, andThen.apply("1")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java new file mode 100644 index 000000000..804b77ca0 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java @@ -0,0 +1,42 @@ +package com.jnape.palatable.lambda.functions.specialized.checked; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.builtin.fn1.Constantly; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; +import static org.junit.Assert.assertEquals; + +public class CheckedSupplierTest { + + @Test + public void assignment() { + CheckedSupplier intSupplier = checked(() -> 1); + CheckedSupplier fmap = intSupplier.fmap(Object::toString); + @SuppressWarnings("RedundantTypeArguments") + CheckedSupplier flatMap = intSupplier.flatMap(Constantly::constantly); + CheckedSupplier discardL = intSupplier.discardL(constantly(1)); + CheckedSupplier discardR = intSupplier.discardR(constantly(2)); + CheckedSupplier zipA = intSupplier.zip(constantly(id())); + CheckedSupplier zipF = intSupplier.zip(constantly()); + CheckedSupplier diMapR = intSupplier.diMapR(id()); + CheckedSupplier> carry = intSupplier.carry(); + CheckedSupplier andThen = intSupplier.andThen(id()); + + assertEquals((Integer) 1, intSupplier.get()); + assertEquals("1", fmap.get()); + assertEquals((Integer) 1, flatMap.get()); + assertEquals((Integer) 1, discardL.get()); + assertEquals((Integer) 1, discardR.get()); + assertEquals((Integer) 1, zipA.get()); + assertEquals(UNIT, zipF.get()); + assertEquals((Integer) 1, diMapR.get()); + assertEquals(tuple(UNIT, 1), carry.get()); + assertEquals((Integer) 1, andThen.get()); + } +} \ No newline at end of file From 72691024bc18ba7f41e8ebb6256de5cda0374fd0 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Jan 2019 18:15:22 -0600 Subject: [PATCH 097/348] MapLens#valueAt and MapLens#asCopy receive overloads that take copyFn --- CHANGELOG.md | 2 + .../palatable/lambda/lens/lenses/MapLens.java | 55 ++++++++++++++----- .../lambda/lens/lenses/MapLensTest.java | 46 ++++++++++++++-- 3 files changed, 83 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fc01f1a3..613d8ef79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `CheckedEffect` is now a `CheckedFn1` - `CheckedSupplier` is now a `CheckedFn1` - `CheckedFn1` now overrides all possible methods with covariant return type +- `MapLens#asCopy` has overload taking copy function +- `MapLens#valueAt` has overload taking copy function ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java index d01bfbd05..d9a1e33b2 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java @@ -2,7 +2,9 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Filter; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.lens.Iso; import com.jnape.palatable.lambda.lens.Lens; @@ -12,12 +14,15 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.maybe; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Alter.alter; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap; import static com.jnape.palatable.lambda.lens.Lens.Simple.adapt; +import static com.jnape.palatable.lambda.lens.Lens.lens; import static com.jnape.palatable.lambda.lens.Lens.simpleLens; import static com.jnape.palatable.lambda.lens.functions.View.view; import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftA; @@ -31,6 +36,20 @@ public final class MapLens { private MapLens() { } + /** + * A lens that focuses on a copy of a {@link Map} as a subtype M. Useful for composition to avoid + * mutating a map reference. + * + * @param the map subtype + * @param the key type + * @param the value type + * @return a lens that focuses on copies of maps as a specific subtype + */ + public static , K, V> Lens, M, M, M> asCopy( + Function, ? extends M> copyFn) { + return lens(copyFn, (__, copy) -> copy); + } + /** * A lens that focuses on a copy of a Map. Useful for composition to avoid mutating a map reference. * @@ -39,7 +58,26 @@ private MapLens() { * @return a lens that focuses on copies of maps */ public static Lens.Simple, Map> asCopy() { - return simpleLens(HashMap::new, (__, copy) -> copy); + return adapt(asCopy(HashMap::new)); + } + + /** + * A lens that focuses on a value at a key in a map, as a {@link Maybe}, and produces a subtype M on + * the way back out. + * + * @param the map subtype + * @param the key type + * @param the value type + * @param k the key to focus on + * @return a lens that focuses on the value at key, as a {@link Maybe} + */ + public static , K, V> Lens, M, Maybe, Maybe> valueAt( + Function, ? extends M> copyFn, K k) { + return lens(m -> maybe(m.get(k)), (m, maybeV) -> maybeV + .>>fmap(v -> alter(updated -> updated.put(k, v))) + .orElse(alter(updated -> updated.remove(k))) + .apply(copyFn.apply(m)) + .unsafePerformIO()); } /** @@ -51,16 +89,7 @@ public static Lens.Simple, Map> asCopy() { * @return a lens that focuses on the value at key, as a {@link Maybe} */ public static Lens.Simple, Maybe> valueAt(K k) { - return simpleLens(m -> maybe(m.get(k)), (m, maybeV) -> { - Map updated = new HashMap<>(m); - return maybeV.fmap(v -> { - updated.put(k, v); - return updated; - }).orElseGet(() -> { - updated.remove(k); - return updated; - }); - }); + return adapt(valueAt(HashMap::new, k)); } /** @@ -75,7 +104,6 @@ public static Lens.Simple, Maybe> valueAt(K k) { * @param the value type * @return a lens that focuses on the value at the key */ - @SuppressWarnings("unchecked") public static Lens.Simple, V> valueAt(K k, V defaultValue) { return adapt(unLiftB(unLiftA(valueAt(k), defaultValue))); } @@ -150,8 +178,7 @@ public static Lens.Simple, Map> inverted() { /** * A lens that focuses on a map while mapping its values with the mapping {@link Iso}. *

- * Note that for this lens to be lawful, iso must be bijective: that is, every V must - * uniquely and invertibly map to exactly one V2. + * Note that for this lens to be lawful, iso must be lawful. * * @param iso the mapping {@link Iso} * @param the key type diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java b/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java index dc18edd90..7a83e934a 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java @@ -6,6 +6,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.Map; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -15,7 +16,6 @@ import static com.jnape.palatable.lambda.lens.functions.View.view; import static com.jnape.palatable.lambda.lens.lenses.MapLens.keys; import static com.jnape.palatable.lambda.lens.lenses.MapLens.mappingValues; -import static com.jnape.palatable.lambda.lens.lenses.MapLens.valueAt; import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; @@ -27,11 +27,12 @@ import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertThat; import static testsupport.assertion.LensAssert.assertLensLawfulness; +import static testsupport.matchers.IterableMatcher.iterates; public class MapLensTest { @Test - public void asCopyFocusesOnMapThroughCopy() { + public void asCopy() { assertLensLawfulness(MapLens.asCopy(), asList(emptyMap(), singletonMap("foo", 1), new HashMap() {{ put("foo", 1); @@ -46,8 +47,29 @@ public void asCopyFocusesOnMapThroughCopy() { } @Test - public void valueAtFocusesOnValueAtKey() { - assertLensLawfulness(valueAt("foo"), + public void asCopyWithCopyFn() { + assertLensLawfulness(MapLens.asCopy(LinkedHashMap::new), + asList(emptyMap(), singletonMap("foo", 1), new HashMap() {{ + put("foo", 1); + put("bar", 2); + put("baz", 3); + }}), + asList(emptyMap(), singletonMap("foo", 1), new HashMap() {{ + put("foo", 1); + put("bar", 2); + put("baz", 3); + }})); + + assertThat(view(MapLens.asCopy(LinkedHashMap::new), new LinkedHashMap() {{ + put("foo", 1); + put("bar", 2); + put("baz", 3); + }}).keySet(), iterates("foo", "bar", "baz")); + } + + @Test + public void valueAt() { + assertLensLawfulness(MapLens.valueAt("foo"), asList(emptyMap(), singletonMap("foo", 1), new HashMap() {{ put("foo", 1); put("bar", 2); @@ -57,8 +79,20 @@ public void valueAtFocusesOnValueAtKey() { } @Test - public void valueAtWithDefaultValueFocusedOnValueAtKey() { - Lens.Simple, Integer> atFoo = valueAt("foo", -1); + public void valueAtWithCopyFn() { + assertLensLawfulness(MapLens.valueAt("foo"), + asList(emptyMap(), singletonMap("foo", 1), new HashMap() {{ + put("foo", 1); + put("bar", 2); + put("baz", 3); + }}), + asList(nothing(), just(1))); + } + + + @Test + public void valueAtWithDefaultValue() { + Lens.Simple, Integer> atFoo = MapLens.valueAt("foo", -1); assertEquals((Integer) 1, view(atFoo, new HashMap() {{ put("foo", 1); From 6dc922009fa021c15e2d014a90223db2a29a545b Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Jan 2019 18:27:01 -0600 Subject: [PATCH 098/348] Adding SortWith for sorting given a Comparator --- CHANGELOG.md | 1 + .../lambda/functions/builtin/fn1/Sort.java | 5 +- .../lambda/functions/builtin/fn2/SortBy.java | 11 ++--- .../functions/builtin/fn2/SortWith.java | 48 +++++++++++++++++++ .../functions/builtin/fn2/SortWithTest.java | 22 +++++++++ 5 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWithTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 613d8ef79..edd480a47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `CheckedFn1` now overrides all possible methods with covariant return type - `MapLens#asCopy` has overload taking copy function - `MapLens#valueAt` has overload taking copy function +- `SortWith` for sorting an `Iterable` given a `Comparator` over its elements ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java index ce297dd9b..96fb7056d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java @@ -1,6 +1,8 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn2.SortBy; +import com.jnape.palatable.lambda.functions.builtin.fn2.SortWith; import java.util.List; @@ -12,7 +14,8 @@ * this is both eager and monolithic. * * @param the input Iterable and output List element type - * @see com.jnape.palatable.lambda.functions.builtin.fn2.SortBy + * @see SortBy + * @see SortWith */ public final class Sort> implements Fn1, List> { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java index de395356d..b92628141 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java @@ -2,12 +2,12 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.builtin.fn1.Sort; -import java.util.ArrayList; import java.util.List; import java.util.function.Function; -import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; +import static com.jnape.palatable.lambda.functions.builtin.fn2.SortWith.sortWith; import static java.util.Comparator.comparing; /** @@ -17,7 +17,8 @@ * * @param the input Iterable and output List element type * @param the mapped Comparable type - * @see com.jnape.palatable.lambda.functions.builtin.fn1.Sort + * @see Sort + * @see SortWith */ public final class SortBy> implements Fn2, Iterable, List> { @@ -28,9 +29,7 @@ private SortBy() { @Override public List apply(Function fn, Iterable as) { - List result = toCollection(ArrayList::new, as); - result.sort(comparing(fn)); - return result; + return sortWith(comparing(fn), as); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java new file mode 100644 index 000000000..813fb2e53 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java @@ -0,0 +1,48 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.builtin.fn1.Sort; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; + +/** + * Given an {@link Iterable} and a {@link java.util.Comparator} over the {@link Iterable} element type, produce a + * sorted {@link List} of the original elements based on sorting applied by the {@link java.util.Comparator}. Note that + * this is both eager and monolithic. + * + * @param the input Iterable and output List element type + * @see Sort + * @see SortBy + */ +public final class SortWith implements Fn2, Iterable, List> { + + private static final SortWith INSTANCE = new SortWith(); + + private SortWith() { + } + + @Override + public List apply(Comparator comparator, Iterable as) { + List result = toCollection(ArrayList::new, as); + result.sort(comparator); + return result; + } + + @SuppressWarnings("unchecked") + public static SortWith sortWith() { + return INSTANCE; + } + + public static Fn1, List> sortWith(Comparator comparator) { + return SortWith.sortWith().apply(comparator); + } + + public static List sortWith(Comparator comparator, Iterable as) { + return SortWith.sortWith(comparator).apply(as); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWithTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWithTest.java new file mode 100644 index 000000000..d1b64b603 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWithTest.java @@ -0,0 +1,22 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import org.junit.Test; + +import java.util.Comparator; + +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn2.SortWith.sortWith; +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +public class SortWithTest { + + @Test + public void sortsWithGivenComparator() { + assertEquals(asList(tuple("bar", 4), tuple("baz", 3), tuple("foo", 1), tuple("foo", 2)), + sortWith(Comparator., String>comparing(Tuple2::_1) + .thenComparing(Tuple2::_2), + asList(tuple("foo", 1), tuple("foo", 2), tuple("bar", 4), tuple("baz", 3)))); + } +} \ No newline at end of file From 7bc9def4dde6546bb168990f3ec5fa63ea6bcd5b Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 27 Jan 2019 18:07:03 -0600 Subject: [PATCH 099/348] Adding the ability to supply an IO with externally managed futures --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/io/IO.java | 64 ++++++++++++++++++- .../com/jnape/palatable/lambda/io/IOTest.java | 25 ++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edd480a47..8018ab1d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `MapLens#asCopy` has overload taking copy function - `MapLens#valueAt` has overload taking copy function - `SortWith` for sorting an `Iterable` given a `Comparator` over its elements +- `IO#externallyManaged`, for supplying an `IO` with externally-managed futures ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index cac71ebd9..a34333b35 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -5,9 +5,14 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; import java.util.function.Function; +import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; +import static java.util.concurrent.CompletableFuture.supplyAsync; /** * A {@link Monad} representing some effectful computation to be performed. @@ -17,12 +22,38 @@ public interface IO extends Monad> { /** - * Run the effect represented by this {@link IO} instance + * Run the effect represented by this {@link IO} instance, blocking the current thread until the effect terminates. * * @return the result of the effect */ A unsafePerformIO(); + /** + * Returns a {@link CompletableFuture} representing the result of this eventual effect. By default, this will + * immediately run the effect in terms of the implicit {@link Executor} available to {@link CompletableFuture} + * (usually the {@link java.util.concurrent.ForkJoinPool}). Note that specific {@link IO} constructions may allow + * this method to delegate to externally-managed {@link CompletableFuture} instead of synthesizing their own. + * + * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result + * @see IO#unsafePerformAsyncIO(Executor) + */ + default CompletableFuture unsafePerformAsyncIO() { + return supplyAsync(this::unsafePerformIO); + } + + /** + * Returns a {@link CompletableFuture} representing the result of this eventual effect. By default, this will + * immediately run the effect in terms of the provided {@link Executor}. Note that specific {@link IO} + * constructions may allow this method to delegate to externally-managed {@link CompletableFuture} instead of + * synthesizing their own. + * + * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result + * @see IO#unsafePerformAsyncIO() + */ + default CompletableFuture unsafePerformAsyncIO(Executor executor) { + return supplyAsync(this::unsafePerformIO, executor); + } + /** * {@inheritDoc} */ @@ -116,4 +147,35 @@ static IO io(Runnable runnable) { static IO io(Fn1 fn1) { return io(() -> fn1.apply(UNIT)); } + + /** + * Static factory method for creating an {@link IO} from an externally managed source of + * {@link CompletableFuture completable futures}. + *

+ * Note that constructing an {@link IO} this way results in no intermediate futures being constructed by either + * {@link IO#unsafePerformAsyncIO()} or {@link IO#unsafePerformAsyncIO(Executor)}, and {@link IO#unsafePerformIO()} + * is synonymous with invoking {@link CompletableFuture#get()} on the externally managed future. + * + * @param supplier the source of externally managed {@link CompletableFuture completable futures} + * @param the result type + * @return the {@link IO} + */ + static IO externallyManaged(Supplier> supplier) { + return new IO() { + @Override + public A unsafePerformIO() { + return checked(() -> unsafePerformAsyncIO().get()).get(); + } + + @Override + public CompletableFuture unsafePerformAsyncIO() { + return supplier.get(); + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return supplier.get(); + } + }; + } } diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 3ebe09425..0af0d2bd4 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -9,9 +9,15 @@ import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import java.util.concurrent.CompletableFuture; + import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.Fn0.fn0; +import static com.jnape.palatable.lambda.io.IO.externallyManaged; import static com.jnape.palatable.lambda.io.IO.io; +import static java.util.concurrent.CompletableFuture.completedFuture; +import static java.util.concurrent.Executors.newFixedThreadPool; +import static java.util.concurrent.ForkJoinPool.commonPool; import static org.junit.Assert.assertEquals; @RunWith(Traits.class) @@ -29,4 +35,23 @@ public void staticFactoryMethods() { assertEquals((Integer) 1, io(fn0(() -> 1)).unsafePerformIO()); assertEquals(UNIT, io(() -> {}).unsafePerformIO()); } + + @Test(timeout = 100) + public void unsafePerformAsyncIOWithoutExecutor() { + assertEquals((Integer) 1, io(() -> 1).unsafePerformAsyncIO().join()); + } + + @Test(timeout = 100) + public void unsafePerformAsyncIOWithExecutor() { + assertEquals((Integer) 1, io(() -> 1).unsafePerformAsyncIO(newFixedThreadPool(1)).join()); + } + + @Test + public void delegatesToExternallyManagedFuture() { + CompletableFuture future = completedFuture(1); + IO io = externallyManaged(() -> future); + assertEquals((Integer) 1, io.unsafePerformIO()); + assertEquals((Integer) 1, io.unsafePerformAsyncIO().join()); + assertEquals((Integer) 1, io.unsafePerformAsyncIO(commonPool()).join()); + } } \ No newline at end of file From 8bac98500f2cb84e4a7f6bc15b06e0c85d6bdcf5 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 27 Jan 2019 18:12:56 -0600 Subject: [PATCH 100/348] publishing test-jar --- CHANGELOG.md | 1 + pom.xml | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8018ab1d4..621387672 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `MapLens#valueAt` has overload taking copy function - `SortWith` for sorting an `Iterable` given a `Comparator` over its elements - `IO#externallyManaged`, for supplying an `IO` with externally-managed futures +- test jar is now published ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect diff --git a/pom.xml b/pom.xml index 977cbab29..da6a3b5c6 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -57,6 +58,7 @@ 1.2 3.3 1.3 + 3.1.1 @@ -103,6 +105,18 @@ + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + + test-jar + + + + From 7f23b8fe550396e4281b8bf98de06c7b1a992196 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 27 Jan 2019 18:24:46 -0600 Subject: [PATCH 101/348] Moving IO back until a future release --- .../java/com/jnape/palatable/lambda/functions/Effect.java | 3 +-- src/main/java/com/jnape/palatable/lambda/functions/Fn0.java | 2 +- .../com/jnape/palatable/lambda/{io => functions}/IO.java | 3 +-- .../jnape/palatable/lambda/functions/builtin/fn2/Alter.java | 2 +- .../lambda/functions/specialized/checked/CheckedEffect.java | 4 ++-- .../functions/specialized/checked/CheckedRunnable.java | 2 +- .../com/jnape/palatable/lambda/lens/lenses/MapLens.java | 2 +- .../com/jnape/palatable/lambda/monoid/builtin/RunAll.java | 4 ++-- .../jnape/palatable/lambda/semigroup/builtin/RunAll.java | 2 +- .../jnape/palatable/lambda/{io => functions}/IOTest.java | 6 +++--- .../jnape/palatable/lambda/monoid/builtin/RunAllTest.java | 2 +- .../palatable/lambda/semigroup/builtin/RunAllTest.java | 2 +- src/test/java/testsupport/EqualityAwareIO.java | 2 +- 13 files changed, 17 insertions(+), 19 deletions(-) rename src/main/java/com/jnape/palatable/lambda/{io => functions}/IO.java (98%) rename src/test/java/com/jnape/palatable/lambda/{io => functions}/IOTest.java (91%) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 4712299b7..89a2d6858 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -2,13 +2,12 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.io.IO; import java.util.function.Consumer; import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn0.fn0; -import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.functions.IO.io; /** * A function returning "no result", and therefore only useful as a side-effect. diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index 74d742cbc..84eb3e4a8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -9,7 +9,7 @@ import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.functions.IO.io; /** * A function taking "no arguments", implemented as an {@link Fn1}<{@link Unit}, A>. diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/functions/IO.java similarity index 98% rename from src/main/java/com/jnape/palatable/lambda/io/IO.java rename to src/main/java/com/jnape/palatable/lambda/functions/IO.java index a34333b35..ba77a8c66 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/IO.java @@ -1,7 +1,6 @@ -package com.jnape.palatable.lambda.io; +package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java index 488de31ce..f51050eae 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.functions.IO; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java index 7e1a42fa5..a4dc0c820 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java @@ -4,13 +4,13 @@ import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.functions.IO; import java.util.function.Consumer; import java.util.function.Function; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; -import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.functions.IO.io; /** * Specialized {@link Effect} that can throw any {@link Throwable}. diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java index 358072f93..7eb794917 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.functions.specialized.checked; import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.functions.IO; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java index d9a1e33b2..a9e1a2d9f 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java @@ -4,7 +4,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Filter; -import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.functions.IO; import com.jnape.palatable.lambda.lens.Iso; import com.jnape.palatable.lambda.lens.Lens; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java index 871deebb1..8e3c0d869 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java @@ -1,12 +1,12 @@ package com.jnape.palatable.lambda.monoid.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.functions.IO; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; import com.jnape.palatable.lambda.monoid.Monoid; import com.jnape.palatable.lambda.semigroup.Semigroup; -import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.functions.IO.io; import static com.jnape.palatable.lambda.monoid.Monoid.monoid; /** diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java index b46ff9612..5ae09b8ac 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.functions.IO; import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; import com.jnape.palatable.lambda.semigroup.Semigroup; diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java similarity index 91% rename from src/test/java/com/jnape/palatable/lambda/io/IOTest.java rename to src/test/java/com/jnape/palatable/lambda/functions/IOTest.java index 0af0d2bd4..c10aea5c5 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.io; +package com.jnape.palatable.lambda.functions; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; @@ -13,8 +13,8 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.Fn0.fn0; -import static com.jnape.palatable.lambda.io.IO.externallyManaged; -import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.functions.IO.externallyManaged; +import static com.jnape.palatable.lambda.functions.IO.io; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.Executors.newFixedThreadPool; import static java.util.concurrent.ForkJoinPool.commonPool; diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java index c0e9f6d17..782ee334f 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.monoid.Monoid; import org.junit.Test; -import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.functions.IO.io; import static com.jnape.palatable.lambda.monoid.builtin.RunAll.runAll; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java index 329fe8429..c8840da69 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.semigroup.Semigroup; import org.junit.Test; -import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.functions.IO.io; import static com.jnape.palatable.lambda.semigroup.builtin.RunAll.runAll; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/testsupport/EqualityAwareIO.java b/src/test/java/testsupport/EqualityAwareIO.java index ac1d56f14..822cfebf7 100644 --- a/src/test/java/testsupport/EqualityAwareIO.java +++ b/src/test/java/testsupport/EqualityAwareIO.java @@ -1,6 +1,6 @@ package testsupport; -import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.functions.IO; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; From 9c1c6d42901b237ecc81d39eaa5d08b0d0378291 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 27 Jan 2019 19:44:09 -0600 Subject: [PATCH 102/348] Adding Monad#join, alias of flatMap(id()) --- CHANGELOG.md | 1 + .../jnape/palatable/lambda/monad/Monad.java | 18 ++++++++++++- .../java/testsupport/traits/MonadLaws.java | 25 +++++++++++++------ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 621387672..19c8332b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `SortWith` for sorting an `Iterable` given a `Comparator` over its elements - `IO#externallyManaged`, for supplying an `IO` with externally-managed futures - test jar is now published +- `Monad#join` static alias for `flatMap(id())` ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect diff --git a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java index 11b18d84c..4c3e2e18d 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java @@ -1,9 +1,12 @@ package com.jnape.palatable.lambda.monad; +import com.jnape.palatable.lambda.functions.builtin.fn1.Id; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; + /** * Monads are {@link Applicative} functors that support a flattening operation to unwrap M<M<A>> * -> M<A>. This flattening operation, coupled with {@link Applicative#zip(Applicative)}, gives rise to @@ -53,7 +56,7 @@ default Monad fmap(Function fn) { */ @Override default Monad zip(Applicative, M> appFn) { - return appFn., M>>coerce().flatMap(ab -> fmap(ab::apply)); + return appFn., M>>coerce().flatMap(this::fmap); } /** @@ -71,4 +74,17 @@ default Monad discardL(Applicative appB) { default Monad discardR(Applicative appB) { return Applicative.super.discardR(appB).coerce(); } + + /** + * Convenience static method equivalent to {@link Monad#flatMap(Function) flatMap}{@link Id#id() (id())}; + * + * @param mma the outer monad + * @param the monad type + * @param the nested type parameter + * @param the nested monad + * @return the nested monad + */ + static > MA join(Monad mma) { + return mma.flatMap(id()).coerce(); + } } \ No newline at end of file diff --git a/src/test/java/testsupport/traits/MonadLaws.java b/src/test/java/testsupport/traits/MonadLaws.java index da7ba9e66..038fc6789 100644 --- a/src/test/java/testsupport/traits/MonadLaws.java +++ b/src/test/java/testsupport/traits/MonadLaws.java @@ -12,6 +12,8 @@ import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; +import static com.jnape.palatable.lambda.monad.Monad.join; import static java.util.Arrays.asList; public class MonadLaws implements Trait> { @@ -22,7 +24,8 @@ public void test(Monad m) { ., Maybe>>foldMap(f -> f.apply(m), asList( this::testLeftIdentity, this::testRightIdentity, - this::testAssociativity)) + this::testAssociativity, + this::testJoin)) .peek(s -> { throw new AssertionError("The following Monad laws did not hold for instance of " + m.getClass() + ": \n\t - " + s); }); @@ -32,21 +35,29 @@ private Maybe testLeftIdentity(Monad m) { Object a = new Object(); Fn1> fn = id().andThen(m::pure); return m.pure(a).flatMap(fn).equals(fn.apply(a)) - ? nothing() - : just("left identity (m.pure(a).flatMap(fn).equals(fn.apply(a)))"); + ? nothing() + : just("left identity (m.pure(a).flatMap(fn).equals(fn.apply(a)))"); } private Maybe testRightIdentity(Monad m) { return m.flatMap(m::pure).equals(m) - ? nothing() - : just("right identity: (m.flatMap(m::pure).equals(m))"); + ? nothing() + : just("right identity: (m.flatMap(m::pure).equals(m))"); } private Maybe testAssociativity(Monad m) { Fn1> f = constantly(m.pure(new Object())); Function> g = constantly(m.pure(new Object())); return m.flatMap(f).flatMap(g).equals(m.flatMap(a -> f.apply(a).flatMap(g))) - ? nothing() - : just("associativity: (m.flatMap(f).flatMap(g).equals(m.flatMap(a -> f.apply(a).flatMap(g))))"); + ? nothing() + : just("associativity: (m.flatMap(f).flatMap(g).equals(m.flatMap(a -> f.apply(a).flatMap(g))))"); + } + + private Maybe testJoin(Monad m) { + Monad, M> mma = m.pure(m.fmap(upcast())); + boolean equals = mma.flatMap(id()).equals(join(mma)); + return equals + ? nothing() + : just("join: (m.pure(m).flatMap(id())).equals(Monad.join(m.pure(m)))"); } } From 9e2fb489235280bb8b0a0a9025da055e244e9a43 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 27 Jan 2019 19:51:58 -0600 Subject: [PATCH 103/348] Fixing javadoc --- .../jnape/palatable/lambda/functions/IO.java | 1 + .../palatable/lambda/lens/lenses/MapLens.java | 18 ++++++++++-------- .../lambda/monoid/builtin/MergeMaps.java | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/IO.java b/src/main/java/com/jnape/palatable/lambda/functions/IO.java index ba77a8c66..f6eed028d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/IO.java @@ -46,6 +46,7 @@ default CompletableFuture unsafePerformAsyncIO() { * constructions may allow this method to delegate to externally-managed {@link CompletableFuture} instead of * synthesizing their own. * + * @param executor the {@link Executor} to run the {@link CompletableFuture} from * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result * @see IO#unsafePerformAsyncIO() */ diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java index a9e1a2d9f..e6df4f236 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java @@ -3,8 +3,8 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.builtin.fn2.Filter; import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.functions.builtin.fn2.Filter; import com.jnape.palatable.lambda.lens.Iso; import com.jnape.palatable.lambda.lens.Lens; @@ -40,9 +40,10 @@ private MapLens() { * A lens that focuses on a copy of a {@link Map} as a subtype M. Useful for composition to avoid * mutating a map reference. * - * @param the map subtype - * @param the key type - * @param the value type + * @param the map subtype + * @param the key type + * @param the value type + * @param copyFn the copy function * @return a lens that focuses on copies of maps as a specific subtype */ public static , K, V> Lens, M, M, M> asCopy( @@ -65,10 +66,11 @@ public static Lens.Simple, Map> asCopy() { * A lens that focuses on a value at a key in a map, as a {@link Maybe}, and produces a subtype M on * the way back out. * - * @param the map subtype - * @param the key type - * @param the value type - * @param k the key to focus on + * @param the map subtype + * @param the key type + * @param the value type + * @param k the key to focus on + * @param copyFn the copy function * @return a lens that focuses on the value at key, as a {@link Maybe} */ public static , K, V> Lens, M, Maybe, Maybe> valueAt( diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java index 8de8ffdc2..104d6f7d5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java @@ -11,8 +11,8 @@ import java.util.function.Supplier; /** - * A {@link Monoid} instance formed by {@link Map#merge(K, V, BiFunction)} and a semigroup over V. - * Combines together multiple maps using the provided semigroup for key collisions. + * A {@link Monoid} instance formed by {@link java.util.Map#merge(Object, Object, BiFunction)} and a semigroup over + * V. Combines together multiple maps using the provided semigroup for key collisions. * * @param The key parameter type of the Map * @param The value parameter type of the Map From ed2e477a9127e0417304582d067fc30aba3cfc25 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 2 Feb 2019 17:31:25 -0600 Subject: [PATCH 104/348] Adding static factory method to create an Effect from an Fn1 --- CHANGELOG.md | 1 + .../palatable/lambda/functions/Effect.java | 22 ++++++++++++++----- .../lambda/functions/EffectTest.java | 17 ++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19c8332b5..b95a5e235 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `IO#externallyManaged`, for supplying an `IO` with externally-managed futures - test jar is now published - `Monad#join` static alias for `flatMap(id())` +- `Effect#effect` static factory method taking `Fn1` ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 89a2d6858..5c36ff861 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -8,6 +8,7 @@ import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** * A function returning "no result", and therefore only useful as a side-effect. @@ -26,22 +27,22 @@ default IO apply(A a) { @Override default Effect diMapL(Function fn) { - return effect(z -> Fn1.super.diMapL(fn).apply(z).unsafePerformIO()); + return effect(Fn1.super.diMapL(fn)); } @Override default Effect contraMap(Function fn) { - return effect(z -> Fn1.super.contraMap(fn).apply(z).unsafePerformIO()); + return effect(Fn1.super.contraMap(fn)); } @Override default Effect compose(Function before) { - return effect(z -> Fn1.super.compose(before).apply(z).unsafePerformIO()); + return effect(Fn1.super.compose(before)); } @Override default Effect discardR(Applicative> appB) { - return effect(a -> Fn1.super.discardR(appB).apply(a).unsafePerformIO()); + return effect(Fn1.super.discardR(appB)); } @Override @@ -67,6 +68,17 @@ static Effect effect(Consumer effect) { * @return the effect */ static Effect effect(Runnable runnable) { - return effect(__ -> runnable.run()); + return effect(constantly(io(runnable))); + } + + /** + * Create an {@link Effect} from an {@link Fn1} that yields an {@link IO}. + * + * @param fn the function + * @param the effect argument type + * @return the effect + */ + static Effect effect(Fn1> fn) { + return a -> fn.apply(a).unsafePerformIO(); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java index dd38e6add..9f5dabd60 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java @@ -1,10 +1,14 @@ package com.jnape.palatable.lambda.functions; +import com.jnape.palatable.lambda.adt.Unit; import org.junit.Test; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.Effect.effect; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; @@ -31,4 +35,17 @@ public void covariantReturns() { assertEquals(asList("1", "2", "3", "4", "5", "6", "6"), results); } + + @Test + public void staticFactoryMethods() { + AtomicInteger counter = new AtomicInteger(); + + Effect runnableEffect = effect(counter::incrementAndGet); + runnableEffect.apply(UNIT).unsafePerformIO(); + assertEquals(1, counter.get()); + + Effect fnEffect = effect(AtomicInteger::incrementAndGet); + fnEffect.apply(counter).unsafePerformIO(); + assertEquals(2, counter.get()); + } } \ No newline at end of file From 92255917c3f6ed223eb4104f9fc50474d5f3e680 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 11 Feb 2019 00:21:03 -0600 Subject: [PATCH 105/348] IOs compose automatically parallelizing where possible --- CHANGELOG.md | 1 + .../jnape/palatable/lambda/functions/IO.java | 69 ++++++++++++++++++- .../palatable/lambda/functions/IOTest.java | 66 ++++++++++++++++++ 3 files changed, 133 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b95a5e235..971317425 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - test jar is now published - `Monad#join` static alias for `flatMap(id())` - `Effect#effect` static factory method taking `Fn1` +- `IO`s automatically encode parallelism in composition ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect diff --git a/src/main/java/com/jnape/palatable/lambda/functions/IO.java b/src/main/java/com/jnape/palatable/lambda/functions/IO.java index f6eed028d..cb0ce4c07 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/IO.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.functions; +import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; @@ -14,7 +15,9 @@ import static java.util.concurrent.CompletableFuture.supplyAsync; /** - * A {@link Monad} representing some effectful computation to be performed. + * A {@link Monad} representing some side-effecting computation to be performed. Note that because {@link IO} inherently + * offers an interface supporting parallelism, the optimal execution strategy for any given {@link IO} is encoded in + * its composition. * * @param the result type */ @@ -54,12 +57,55 @@ default CompletableFuture unsafePerformAsyncIO(Executor executor) { return supplyAsync(this::unsafePerformIO, executor); } + /** + * Given a function from any {@link Throwable} to the result type A, if this {@link IO} successfully + * yields a result, return it; otherwise, map the {@link Throwable} to the result type and return that. + * + * @param recoveryFn the recovery function + * @return the guarded {@link IO} + */ + default IO exceptionally(Function recoveryFn) { + return new IO() { + @Override + public A unsafePerformIO() { + return Try.trying(IO.this::unsafePerformIO).recover(recoveryFn); + } + + @Override + public CompletableFuture unsafePerformAsyncIO() { + return IO.this.unsafePerformAsyncIO().exceptionally(recoveryFn::apply); + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return IO.this.unsafePerformAsyncIO(executor).exceptionally(recoveryFn::apply); + } + }; + } + /** * {@inheritDoc} */ @Override default IO flatMap(Function>> f) { - return () -> f.apply(unsafePerformIO()).>coerce().unsafePerformIO(); + return new IO() { + @Override + public B unsafePerformIO() { + return f.apply(IO.this.unsafePerformIO()).>coerce().unsafePerformIO(); + } + + @Override + public CompletableFuture unsafePerformAsyncIO() { + return IO.this.unsafePerformAsyncIO() + .thenCompose(a -> f.apply(a).>coerce().unsafePerformAsyncIO()); + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return IO.this.unsafePerformAsyncIO(executor) + .thenCompose(a -> f.apply(a).>coerce().unsafePerformAsyncIO(executor)); + } + }; } /** @@ -83,7 +129,24 @@ default IO fmap(Function fn) { */ @Override default IO zip(Applicative, IO> appFn) { - return Monad.super.zip(appFn).coerce(); + IO ioA = this; + IO> ioF = appFn.coerce(); + return new IO() { + @Override + public B unsafePerformIO() { + return ioF.unsafePerformIO().apply(ioA.unsafePerformIO()); + } + + @Override + public CompletableFuture unsafePerformAsyncIO() { + return ioF.unsafePerformAsyncIO().thenCompose(ioA.unsafePerformAsyncIO()::thenApply); + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return ioF.unsafePerformAsyncIO(executor).thenCompose(ioA.unsafePerformAsyncIO(executor)::thenApply); + } + }; } /** diff --git a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java b/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java index c10aea5c5..cab2595c0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.functions; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -10,11 +11,16 @@ import testsupport.traits.MonadLaws; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.IO.externallyManaged; import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; +import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1.checked; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.Executors.newFixedThreadPool; import static java.util.concurrent.ForkJoinPool.commonPool; @@ -46,6 +52,40 @@ public void unsafePerformAsyncIOWithExecutor() { assertEquals((Integer) 1, io(() -> 1).unsafePerformAsyncIO(newFixedThreadPool(1)).join()); } + @Test + public void zipAndDerivativesComposesInParallel() { + String a = "foo"; + Fn1> f = tupler(1); + + ExecutorService executor = newFixedThreadPool(2); + CountDownLatch advanceFirst = new CountDownLatch(1); + CountDownLatch advanceSecond = new CountDownLatch(1); + + IO ioA = io(checked(__ -> { + advanceFirst.countDown(); + advanceSecond.await(); + return a; + })); + IO>> ioF = io(checked(__ -> { + advanceFirst.await(); + advanceSecond.countDown(); + return f; + })); + + IO> zip = ioA.zip(ioF); + assertEquals(f.apply(a), zip.unsafePerformAsyncIO().join()); + assertEquals(f.apply(a), zip.unsafePerformAsyncIO(executor).join()); + assertEquals(f.apply(a), zip.unsafePerformAsyncIO(executor).join()); + + IO>> discardL = ioA.discardL(ioF); + assertEquals(f, discardL.unsafePerformAsyncIO().join()); + assertEquals(f, discardL.unsafePerformAsyncIO(executor).join()); + + IO discardR = ioA.discardR(ioF); + assertEquals(a, discardR.unsafePerformAsyncIO().join()); + assertEquals(a, discardR.unsafePerformAsyncIO(executor).join()); + } + @Test public void delegatesToExternallyManagedFuture() { CompletableFuture future = completedFuture(1); @@ -54,4 +94,30 @@ public void delegatesToExternallyManagedFuture() { assertEquals((Integer) 1, io.unsafePerformAsyncIO().join()); assertEquals((Integer) 1, io.unsafePerformAsyncIO(commonPool()).join()); } + + @Test + public void exceptionallyRecoversThrowableToResult() { + IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); + assertEquals("foo", io.exceptionally(Throwable::getMessage).unsafePerformIO()); + + IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ + completeExceptionally(new UnsupportedOperationException("foo")); + }}).exceptionally(e -> e.getCause().getMessage()); + assertEquals("foo", externallyManaged.unsafePerformIO()); + } + + @Test + public void exceptionallyRescuesFutures() { + ExecutorService executor = newFixedThreadPool(2); + + IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); + assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO().join()); + assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO(executor).join()); + + IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ + completeExceptionally(new UnsupportedOperationException("foo")); + }}).exceptionally(e -> e.getCause().getMessage()); + assertEquals("foo", externallyManaged.unsafePerformIO()); + + } } \ No newline at end of file From 45d9f2ea6ec00a4570d048d221391db04604c6b3 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 16 Feb 2019 18:18:49 -0600 Subject: [PATCH 106/348] Removing methods/types deprecated in past release --- .../jnape/palatable/lambda/adt/Either.java | 18 -------- .../lambda/semigroup/builtin/AddAll.java | 44 ------------------- 2 files changed, 62 deletions(-) delete mode 100644 src/main/java/com/jnape/palatable/lambda/semigroup/builtin/AddAll.java 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 dfcb85973..00f3bf787 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -127,24 +127,6 @@ public Either flatMap(FunctionrightFn 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 - * @deprecated in favor of {@link Either#match(Function, Function)} - */ - @Deprecated - public final Either flatMap(Function> leftFn, - Function> rightFn) { - return match(leftFn, rightFn); - } - @Override public final Either invert() { return match(Either::right, Either::left); diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/AddAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/AddAll.java deleted file mode 100644 index fe22ba5c2..000000000 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/AddAll.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.jnape.palatable.lambda.semigroup.builtin; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.monoid.Monoid; -import com.jnape.palatable.lambda.semigroup.Semigroup; - -import java.util.Collection; - -/** - * The {@link Semigroup} instance formed under mutative concatenation for an arbitrary {@link Collection}. The - * collection subtype (C) must support {@link Collection#addAll(Collection)}. - *

- * For the {@link Monoid}, see {@link com.jnape.palatable.lambda.monoid.builtin.AddAll}. - * - * @see Semigroup - * @deprecated in favor of the now non-modifying {@link com.jnape.palatable.lambda.monoid.builtin.AddAll monoid} - */ -@Deprecated -public final class AddAll> implements Semigroup { - - private static final AddAll INSTANCE = new AddAll(); - - private AddAll() { - } - - @Override - public C apply(C xs, C ys) { - xs.addAll(ys); - return xs; - } - - @SuppressWarnings("unchecked") - public static > AddAll addAll() { - return INSTANCE; - } - - public static > Fn1 addAll(C xs) { - return AddAll.addAll().apply(xs); - } - - public static > C addAll(C xs, C ys) { - return addAll(xs).apply(ys); - } -} From 0370557f335253792971e0901a5b03d3d31c0470 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 16 Feb 2019 18:21:11 -0600 Subject: [PATCH 107/348] Updating CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 971317425..ee919be2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect +### Removed +- `AddAll` semigroup, deprecated in previous release +- Dyadic `Either#flatMap()`, deprecated in previous release + ## [3.2.0] - 2018-12-08 ### Changed - ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to `functions.builtin.fn2` package From 6e850281eb38be94fb1553f61069a5162803321b Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 19 Feb 2019 23:16:29 -0600 Subject: [PATCH 108/348] [maven-release-plugin] prepare release lambda-3.3.0 --- pom.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index da6a3b5c6..145522c52 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -10,7 +9,7 @@ lambda - 3.2.1-SNAPSHOT + 3.3.0 jar Lambda From 9b8b8bd4d7d9acfb6fc232cfd7a749046a76510f Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 19 Feb 2019 23:16:35 -0600 Subject: [PATCH 109/348] [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 145522c52..00b717374 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.3.0 + 3.3.1-SNAPSHOT jar Lambda From 911e54961af0131155c3ec81ea951de41f9203fc Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 10 Mar 2019 15:53:30 -0500 Subject: [PATCH 110/348] Updating CHANGELOG and README --- CHANGELOG.md | 8 +++++++- README.md | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee919be2e..83f665c3b 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 changes + +## [3.3.0] - 2019-02-18 ### Added - `MergeMaps`, a `Monoid` on `Map` formed by `Map#merge` - `CheckedEffect` is now a `CheckedFn1` @@ -16,7 +19,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - test jar is now published - `Monad#join` static alias for `flatMap(id())` - `Effect#effect` static factory method taking `Fn1` +- `IO#unsafePerformAsyncIO` overloads for running `IO`s asynchronously - `IO`s automatically encode parallelism in composition +- `IO#exceptionally` for recovering from failure during `IO` operation ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect @@ -426,7 +431,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.2.0...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-3.3.0...HEAD +[3.3.0]: https://github.com/palatable/lambda/compare/lambda-3.2.0...3.3.0 [3.2.0]: https://github.com/palatable/lambda/compare/lambda-3.1.0...lambda-3.2.0 [3.1.0]: https://github.com/palatable/lambda/compare/lambda-3.0.3...lambda-3.1.0 [3.0.3]: https://github.com/palatable/lambda/compare/lambda-3.0.2...lambda-3.0.3 diff --git a/README.md b/README.md index 65501c222..d4c933638 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 3.2.0 + 3.3.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '3.2.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '3.3.0' ``` Examples From 8e887966e656a34c0d0e4e47f081a2549051a6c8 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 28 Mar 2019 19:03:44 -0500 Subject: [PATCH 111/348] IO internal rewrite - now sealed - linear and recursive composition is stack-safe - static factory methods are now much easier to infer --- CHANGELOG.md | 6 +- .../palatable/lambda/functions/Effect.java | 3 +- .../jnape/palatable/lambda/functions/Fn0.java | 6 +- .../jnape/palatable/lambda/functions/IO.java | 222 +++++++++++------- .../specialized/checked/CheckedEffect.java | 4 +- .../specialized/checked/CheckedRunnable.java | 9 +- .../palatable/lambda/functions/IOTest.java | 70 +++++- .../java/testsupport/EqualityAwareIO.java | 36 ++- 8 files changed, 225 insertions(+), 131 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83f665c3b..ac54fccb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ 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 changes +### Changed +- ***Breaking Change***: `IO` is now sealed. Most previous constructions using the static factory methods +should continue to work (by simply targeting `Supplier` now instead of an anonymous `IO`), but some might +need to be reworked, and subtyping is obviously no longer supported. +- `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ## [3.3.0] - 2019-02-18 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 5c36ff861..ea5bef72f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -6,7 +6,6 @@ import java.util.function.Consumer; import java.util.function.Function; -import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.IO.io; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -22,7 +21,7 @@ public interface Effect extends Fn1>, Consumer { @Override default IO apply(A a) { - return io(fn0(() -> accept(a))); + return io(() -> accept(a)); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index 84eb3e4a8..a1c67f5cc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -9,7 +9,6 @@ import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.IO.io; /** * A function taking "no arguments", implemented as an {@link Fn1}<{@link Unit}, A>. @@ -124,7 +123,10 @@ static Fn0 fn0(Fn0 fn) { * @return the {@link Fn0} */ static Fn0 fn0(Runnable runnable) { - return io(runnable)::unsafePerformIO; + return fn0(() -> { + runnable.run(); + return UNIT; + }); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/IO.java b/src/main/java/com/jnape/palatable/lambda/functions/IO.java index cb0ce4c07..a71dddebf 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/IO.java @@ -2,17 +2,29 @@ import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; +import java.util.LinkedList; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Function; import java.util.function.Supplier; -import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.choice.Choice2.a; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; +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 com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; +import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.CompletableFuture.supplyAsync; +import static java.util.concurrent.ForkJoinPool.commonPool; /** * A {@link Monad} representing some side-effecting computation to be performed. Note that because {@link IO} inherently @@ -21,14 +33,17 @@ * * @param the result type */ -public interface IO extends Monad> { +public abstract class IO implements Monad> { + + private IO() { + } /** * Run the effect represented by this {@link IO} instance, blocking the current thread until the effect terminates. * * @return the result of the effect */ - A unsafePerformIO(); + public abstract A unsafePerformIO(); /** * Returns a {@link CompletableFuture} representing the result of this eventual effect. By default, this will @@ -39,8 +54,8 @@ public interface IO extends Monad> { * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result * @see IO#unsafePerformAsyncIO(Executor) */ - default CompletableFuture unsafePerformAsyncIO() { - return supplyAsync(this::unsafePerformIO); + public final CompletableFuture unsafePerformAsyncIO() { + return unsafePerformAsyncIO(commonPool()); } /** @@ -53,9 +68,7 @@ default CompletableFuture unsafePerformAsyncIO() { * @return the {@link CompletableFuture} representing this {@link IO}'s eventual result * @see IO#unsafePerformAsyncIO() */ - default CompletableFuture unsafePerformAsyncIO(Executor executor) { - return supplyAsync(this::unsafePerformIO, executor); - } + public abstract CompletableFuture unsafePerformAsyncIO(Executor executor); /** * Given a function from any {@link Throwable} to the result type A, if this {@link IO} successfully @@ -64,18 +77,13 @@ default CompletableFuture unsafePerformAsyncIO(Executor executor) { * @param recoveryFn the recovery function * @return the guarded {@link IO} */ - default IO exceptionally(Function recoveryFn) { + public final IO exceptionally(Function recoveryFn) { return new IO() { @Override public A unsafePerformIO() { return Try.trying(IO.this::unsafePerformIO).recover(recoveryFn); } - @Override - public CompletableFuture unsafePerformAsyncIO() { - return IO.this.unsafePerformAsyncIO().exceptionally(recoveryFn::apply); - } - @Override public CompletableFuture unsafePerformAsyncIO(Executor executor) { return IO.this.unsafePerformAsyncIO(executor).exceptionally(recoveryFn::apply); @@ -87,40 +95,15 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { * {@inheritDoc} */ @Override - default IO flatMap(Function>> f) { - return new IO() { - @Override - public B unsafePerformIO() { - return f.apply(IO.this.unsafePerformIO()).>coerce().unsafePerformIO(); - } - - @Override - public CompletableFuture unsafePerformAsyncIO() { - return IO.this.unsafePerformAsyncIO() - .thenCompose(a -> f.apply(a).>coerce().unsafePerformAsyncIO()); - } - - @Override - public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return IO.this.unsafePerformAsyncIO(executor) - .thenCompose(a -> f.apply(a).>coerce().unsafePerformAsyncIO(executor)); - } - }; + public final IO pure(B b) { + return io(b); } /** * {@inheritDoc} */ @Override - default IO pure(B b) { - return () -> b; - } - - /** - * {@inheritDoc} - */ - @Override - default IO fmap(Function fn) { + public final IO fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } @@ -128,32 +111,19 @@ default IO fmap(Function fn) { * {@inheritDoc} */ @Override - default IO zip(Applicative, IO> appFn) { - IO ioA = this; - IO> ioF = appFn.coerce(); - return new IO() { - @Override - public B unsafePerformIO() { - return ioF.unsafePerformIO().apply(ioA.unsafePerformIO()); - } - - @Override - public CompletableFuture unsafePerformAsyncIO() { - return ioF.unsafePerformAsyncIO().thenCompose(ioA.unsafePerformAsyncIO()::thenApply); - } - - @Override - public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return ioF.unsafePerformAsyncIO(executor).thenCompose(ioA.unsafePerformAsyncIO(executor)::thenApply); - } - }; + public final IO zip(Applicative, IO> appFn) { + @SuppressWarnings("unchecked") + IO source = (IO) this; + @SuppressWarnings("unchecked") + IO> zip = (IO>) (Object) appFn; + return new Compose<>(source, a(zip)); } /** * {@inheritDoc} */ @Override - default IO discardL(Applicative> appB) { + public final IO discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } @@ -161,19 +131,20 @@ default IO discardL(Applicative> appB) { * {@inheritDoc} */ @Override - default IO discardR(Applicative> appB) { + public final IO discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } /** - * Static factory method for coercing a lambda to an {@link IO}. - * - * @param io the lambda to coerce - * @param the result type - * @return the {@link IO} + * {@inheritDoc} */ - static IO io(IO io) { - return io; + @Override + public final IO flatMap(Function>> f) { + @SuppressWarnings("unchecked") + IO source = (IO) this; + @SuppressWarnings({"unchecked", "RedundantCast"}) + Function> flatMap = (Function>) (Object) f; + return new Compose<>(source, Choice2.b(flatMap)); } /** @@ -183,32 +154,49 @@ static IO io(IO io) { * @param the result type * @return the {@link IO} */ - static IO io(A a) { - return io(() -> a); + public static IO io(A a) { + return new IO() { + @Override + public A unsafePerformIO() { + return a; + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return completedFuture(a); + } + }; } /** - * Static factory method for creating an {@link IO} that runs runnable and returns {@link Unit}. + * Static factory method for coercing a lambda to an {@link IO}. * - * @param runnable the {@link Runnable} + * @param supplier the lambda to coerce + * @param the result type * @return the {@link IO} */ - static IO io(Runnable runnable) { - return io(() -> { - runnable.run(); - return UNIT; - }); + public static IO io(Supplier supplier) { + return new IO() { + @Override + public A unsafePerformIO() { + return supplier.get(); + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return supplyAsync(supplier, executor); + } + }; } /** - * Static factory method for creating an {@link IO} from an {@link Fn1}<{@link Unit}, A>. + * Static factory method for creating an {@link IO} that runs runnable and returns {@link Unit}. * - * @param fn1 the {@link Fn1} - * @param the result type + * @param runnable the {@link Runnable} * @return the {@link IO} */ - static IO io(Fn1 fn1) { - return io(() -> fn1.apply(UNIT)); + public static IO io(Runnable runnable) { + return io(fn0(runnable)); } /** @@ -223,22 +211,76 @@ static IO io(Fn1 fn1) { * @param the result type * @return the {@link IO} */ - static IO externallyManaged(Supplier> supplier) { + public static IO externallyManaged(Supplier> supplier) { return new IO() { @Override public A unsafePerformIO() { return checked(() -> unsafePerformAsyncIO().get()).get(); } - @Override - public CompletableFuture unsafePerformAsyncIO() { - return supplier.get(); - } - @Override public CompletableFuture unsafePerformAsyncIO(Executor executor) { return supplier.get(); } }; } + + private static final class Compose extends IO { + private final IO source; + private final Choice2>, Function>> composition; + + private Compose(IO source, + Choice2>, Function>> composition) { + this.source = source; + this.composition = composition; + } + + @Override + public A unsafePerformIO() { + @SuppressWarnings("unchecked") + A result = (A) trampoline(into((source, compositions) -> { + Object res = source.unsafePerformIO(); + return compositions.isEmpty() + ? terminate(res) + : compositions.pop().match( + zip -> recurse(tuple(io(zip.unsafePerformIO().apply(res)), compositions)), + flatMap -> { + IO next = flatMap.apply(res); + return (next instanceof Compose) + ? recurse(((Compose) next).deforest(compositions)) + : recurse(tuple(next, compositions)); + }); + }), deforest(new LinkedList<>())); + + return result; + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + @SuppressWarnings("unchecked") + CompletableFuture future = (CompletableFuture) deforest(new LinkedList<>()) + .into((source, compositions) -> foldLeft( + (io, composition) -> composition + .match(zip -> zip.unsafePerformAsyncIO(executor).thenCompose(io::thenApply), + flatMap -> io.thenComposeAsync(obj -> flatMap.apply(obj) + .unsafePerformAsyncIO(executor))), + source.unsafePerformAsyncIO(executor), + compositions)); + return future; + } + + private Tuple2, LinkedList>, Function>>>> + deforest(LinkedList>, Function>>> branches) { + Tuple2, LinkedList>, Function>>>> args = + tuple(this, branches); + return trampoline(into((source, compositions) -> { + IO leaf = source.source; + compositions.push(source.composition); + return leaf instanceof Compose + ? recurse(tuple((Compose) leaf, compositions)) + : terminate(tuple(leaf, compositions)); + }), args); + } + + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java index a4dc0c820..1d833c91b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java @@ -3,14 +3,14 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.Consumer; import java.util.function.Function; -import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; /** * Specialized {@link Effect} that can throw any {@link Throwable}. diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java index 7eb794917..954f4b952 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java @@ -1,7 +1,6 @@ package com.jnape.palatable.lambda.functions.specialized.checked; import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.functions.IO; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; @@ -14,7 +13,7 @@ * @see CheckedFn1 */ @FunctionalInterface -public interface CheckedRunnable extends Runnable, IO { +public interface CheckedRunnable extends Runnable { /** * A version of {@link Runnable#run()} that can throw checked exceptions. @@ -32,12 +31,6 @@ default void run() { } } - @Override - default Unit unsafePerformIO() { - run(); - return UNIT; - } - /** * Convert this {@link CheckedRunnable} to a {@link CheckedSupplier} that returns {@link Unit}. * diff --git a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java b/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java index cab2595c0..578f458f3 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java @@ -16,11 +16,11 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.IO.externallyManaged; import static com.jnape.palatable.lambda.functions.IO.io; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; -import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1.checked; +import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; +import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.Executors.newFixedThreadPool; import static java.util.concurrent.ForkJoinPool.commonPool; @@ -29,8 +29,10 @@ @RunWith(Traits.class) public class IOTest { + private static final int STACK_EXPLODING_NUMBER = 50_000; + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public IO testSubject() { + public EqualityAwareIO testSubject() { return new EqualityAwareIO<>(io(1)); } @@ -38,7 +40,6 @@ public IO testSubject() { public void staticFactoryMethods() { assertEquals((Integer) 1, io(1).unsafePerformIO()); assertEquals((Integer) 1, io(() -> 1).unsafePerformIO()); - assertEquals((Integer) 1, io(fn0(() -> 1)).unsafePerformIO()); assertEquals(UNIT, io(() -> {}).unsafePerformIO()); } @@ -61,12 +62,12 @@ public void zipAndDerivativesComposesInParallel() { CountDownLatch advanceFirst = new CountDownLatch(1); CountDownLatch advanceSecond = new CountDownLatch(1); - IO ioA = io(checked(__ -> { + IO ioA = io(checked(() -> { advanceFirst.countDown(); advanceSecond.await(); return a; })); - IO>> ioF = io(checked(__ -> { + IO>> ioF = io(checked(() -> { advanceFirst.await(); advanceSecond.countDown(); return f; @@ -118,6 +119,63 @@ public void exceptionallyRescuesFutures() { completeExceptionally(new UnsupportedOperationException("foo")); }}).exceptionally(e -> e.getCause().getMessage()); assertEquals("foo", externallyManaged.unsafePerformIO()); + } + + @Test + public void linearSyncStackSafety() { + assertEquals((Integer) STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), io(0)).unsafePerformIO()); + assertEquals((Integer) STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.zip(f.pure(x -> x + 1)), io(0)).unsafePerformIO()); + assertEquals((Integer) 0, + times(STACK_EXPLODING_NUMBER, f -> f.pure(0).discardR(f), io(0)).unsafePerformIO()); + assertEquals((Integer) 1, + times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardR(f), io(0)).unsafePerformIO()); + assertEquals((Integer) 0, + times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardL(f), io(0)).unsafePerformIO()); + assertEquals((Integer) STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.flatMap(x -> f.pure(x + 1)), io(0)).unsafePerformIO()); + } + + @Test + public void recursiveSyncFlatMapStackSafety() { + assertEquals((Integer) STACK_EXPLODING_NUMBER, + new Fn1, IO>() { + @Override + public IO apply(IO a) { + return a.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(io(x + 1)) : io(x)); + } + }.apply(io(0)).unsafePerformIO()); + + } + + @Test + public void linearAsyncStackSafety() { + assertEquals((Integer) STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), io(0)).unsafePerformAsyncIO().join()); + assertEquals((Integer) STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.zip(f.pure(x -> x + 1)), io(0)).unsafePerformAsyncIO() + .join()); + assertEquals((Integer) 0, + times(STACK_EXPLODING_NUMBER, f -> f.pure(0).discardR(f), io(0)).unsafePerformAsyncIO().join()); + assertEquals((Integer) 1, + times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardR(f), io(0)).unsafePerformAsyncIO().join()); + assertEquals((Integer) 0, + times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardL(f), io(0)).unsafePerformAsyncIO().join()); + assertEquals((Integer) STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.flatMap(x -> f.pure(x + 1)), io(0)).unsafePerformAsyncIO() + .join()); + } + + @Test + public void recursiveAsyncFlatMapStackSafety() { + assertEquals((Integer) STACK_EXPLODING_NUMBER, + new Fn1, IO>() { + @Override + public IO apply(IO a) { + return a.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(io(x + 1)) : io(x)); + } + }.apply(io(0)).unsafePerformAsyncIO().join()); } } \ No newline at end of file diff --git a/src/test/java/testsupport/EqualityAwareIO.java b/src/test/java/testsupport/EqualityAwareIO.java index 822cfebf7..b662f968d 100644 --- a/src/test/java/testsupport/EqualityAwareIO.java +++ b/src/test/java/testsupport/EqualityAwareIO.java @@ -6,9 +6,10 @@ import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.IO.io; import static java.util.Objects.hash; -public final class EqualityAwareIO implements IO { +public final class EqualityAwareIO implements Monad> { private final IO io; public EqualityAwareIO(IO io) { @@ -16,45 +17,40 @@ public EqualityAwareIO(IO io) { } @Override - public A unsafePerformIO() { - return io.unsafePerformIO(); + public EqualityAwareIO flatMap(Function>> f) { + return new EqualityAwareIO<>(io.flatMap(f.andThen(x -> x.>coerce().io))); } @Override - public EqualityAwareIO flatMap(Function>> f) { - return new EqualityAwareIO<>(io.flatMap(f)); - } - - @Override - public EqualityAwareIO fmap(Function f) { - return new EqualityAwareIO<>(io.fmap(f)); + public EqualityAwareIO pure(B b) { + return new EqualityAwareIO<>(io(b)); } @Override - public EqualityAwareIO zip(Applicative, IO> appFn) { - return new EqualityAwareIO<>(io.zip(appFn)); + public EqualityAwareIO fmap(Function fn) { + return new EqualityAwareIO<>(io.fmap(fn)); } @Override - public EqualityAwareIO pure(B b) { - return new EqualityAwareIO<>(io.pure(b)); + public EqualityAwareIO zip(Applicative, EqualityAwareIO> appFn) { + return new EqualityAwareIO<>(io.zip(appFn.>>coerce().io)); } - @Override - public EqualityAwareIO discardL(Applicative> appB) { - return new EqualityAwareIO<>(io.discardL(appB)); + public EqualityAwareIO discardL(Applicative> appB) { + return new EqualityAwareIO<>(io.discardL(appB.>coerce().io)); } @Override - public EqualityAwareIO discardR(Applicative> appB) { - return new EqualityAwareIO<>(io.discardR(appB)); + public EqualityAwareIO discardR(Applicative> appB) { + return new EqualityAwareIO<>(io.discardR(appB.>coerce().io)); } @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { - return other instanceof IO && ((IO) other).unsafePerformIO().equals(unsafePerformIO()); + return other instanceof EqualityAwareIO + && ((EqualityAwareIO) other).io.unsafePerformIO().equals(io.unsafePerformIO()); } @Override From 7cced8cd7b3af70f75418b986b68826d8ad670c9 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 31 Mar 2019 16:18:15 -0500 Subject: [PATCH 112/348] Fixing javadocs for inequality operations --- .../com/jnape/palatable/lambda/functions/builtin/fn2/GT.java | 4 ++-- .../com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java | 4 ++-- .../com/jnape/palatable/lambda/functions/builtin/fn2/LT.java | 4 ++-- .../com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java | 4 ++-- .../jnape/palatable/lambda/functions/builtin/fn3/GTBy.java | 2 +- .../jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java | 2 +- .../jnape/palatable/lambda/functions/builtin/fn3/LTBy.java | 2 +- .../jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java index 3c45e24cd..85cd2018c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java @@ -8,8 +8,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.GTBy.gtBy; /** - * Given two {@link Comparable} values of type A, return true if the first value is strictly - * greater than the second value; otherwise, return false. + * Given two {@link Comparable} values of type A, return true if the second value is strictly + * greater than the first value; otherwise, return false. * * @param the value type * @see GTBy diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java index 23069dd03..a0203984d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java @@ -8,8 +8,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.GTEBy.gteBy; /** - * Given two {@link Comparable} values of type A, return true if the first value is greater - * than or equal to the second value according to {@link Comparable#compareTo(Object)}; otherwise, return false. + * Given two {@link Comparable} values of type A, return true if the second value is greater + * than or equal to the first value according to {@link Comparable#compareTo(Object)}; otherwise, return false. * * @param the value type * @see GTEBy diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java index d6a1d6d99..68f9fe1b2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java @@ -8,8 +8,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.LTBy.ltBy; /** - * Given two {@link Comparable} values of type A, return true if the first value is strictly - * less than the second value; otherwise, return false. + * Given two {@link Comparable} values of type A, return true if the second value is strictly + * less than the first value; otherwise, return false. * * @param the value type * @see LTBy diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java index 19d2424c4..72bdc97ad 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java @@ -8,8 +8,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.LTEBy.lteBy; /** - * Given two {@link Comparable} values of type A, return true if the first value is less than - * or equal to the second value according to {@link Comparable#compareTo(Object)} otherwise, return false. + * Given two {@link Comparable} values of type A, return true if the second value is less than + * or equal to the first value according to {@link Comparable#compareTo(Object)} otherwise, return false. * * @param the value typ * @see LTEBy diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java index 4428784e1..d79910faa 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java @@ -9,7 +9,7 @@ /** * Given a mapping function from some type A to some {@link Comparable} type B and two values - * of type A, return true if the first value is strictly greater than the second value in + * of type A, return true if the second value is strictly greater than the first value in * terms of their mapped B results; otherwise, return false. * * @param the value type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java index 2c5d8ae26..f61fcb4c6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java @@ -11,7 +11,7 @@ /** * Given a mapping function from some type A to some {@link Comparable} type B and two values - * of type A, return true if the first value is greater than or equal to the second value in + * of type A, return true if the second value is greater than or equal to the first value in * terms of their mapped B results according to {@link Comparable#compareTo(Object)}; otherwise, return * false. * diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java index 220a600e8..632cc9da0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java @@ -9,7 +9,7 @@ /** * Given a mapping function from some type A to some {@link Comparable} type B and two values - * of type A, return true if the first value is strictly less than the second value in terms + * of type A, return true if the second value is strictly less than the first value in terms * of their mapped B results; otherwise, return false. * * @param the value type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java index a83fdc9c5..c001a8c89 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java @@ -11,7 +11,7 @@ /** * Given a mapping function from some type A to some {@link Comparable} type B and two values - * of type A, return true if the first value is less than or equal to the second value in + * of type A, return true if the second value is less than or equal to the first value in * terms of their mapped B results according to {@link Comparable#compareTo(Object)}; otherwise, return * false. * From 08ebc8e778ac0f8b63a8fb05981b7ad4d0954643 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 31 Mar 2019 16:22:35 -0500 Subject: [PATCH 113/348] Moving IO to its own package --- CHANGELOG.md | 6 +++--- .../java/com/jnape/palatable/lambda/functions/Effect.java | 3 ++- .../palatable/lambda/functions/builtin/fn2/Alter.java | 2 +- .../functions/specialized/checked/CheckedEffect.java | 4 ++-- .../com/jnape/palatable/lambda/{functions => io}/IO.java | 2 +- .../com/jnape/palatable/lambda/lens/lenses/MapLens.java | 2 +- .../com/jnape/palatable/lambda/monoid/builtin/RunAll.java | 4 ++-- .../jnape/palatable/lambda/semigroup/builtin/RunAll.java | 2 +- .../jnape/palatable/lambda/{functions => io}/IOTest.java | 8 +++++--- .../jnape/palatable/lambda/monoid/builtin/RunAllTest.java | 2 +- .../palatable/lambda/semigroup/builtin/RunAllTest.java | 2 +- src/test/java/testsupport/EqualityAwareIO.java | 4 ++-- 12 files changed, 22 insertions(+), 19 deletions(-) rename src/main/java/com/jnape/palatable/lambda/{functions => io}/IO.java (99%) rename src/test/java/com/jnape/palatable/lambda/{functions => io}/IOTest.java (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac54fccb9..40a692490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Changed -- ***Breaking Change***: `IO` is now sealed. Most previous constructions using the static factory methods -should continue to work (by simply targeting `Supplier` now instead of an anonymous `IO`), but some might -need to be reworked, and subtyping is obviously no longer supported. +- ***Breaking Change***: `IO` is now sealed and moved to its own package. Most previous constructions using the static +factory methods should continue to work (by simply targeting `Supplier` now instead of an anonymous `IO`), but some +might need to be reworked, and subtyping is obviously no longer supported. - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ## [3.3.0] - 2019-02-18 diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index ea5bef72f..c08a44b01 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -2,11 +2,12 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.io.IO; import java.util.function.Consumer; import java.util.function.Function; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java index f51050eae..488de31ce 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java index 1d833c91b..0dc24e4bb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java @@ -3,13 +3,13 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.Consumer; import java.util.function.Function; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java similarity index 99% rename from src/main/java/com/jnape/palatable/lambda/functions/IO.java rename to src/main/java/com/jnape/palatable/lambda/io/IO.java index a71dddebf..d659e35a8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.functions; +package com.jnape.palatable.lambda.io; import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.adt.Unit; diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java index e6df4f236..63823404f 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functions.builtin.fn2.Filter; import com.jnape.palatable.lambda.lens.Iso; import com.jnape.palatable.lambda.lens.Lens; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java index 8e3c0d869..871deebb1 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java @@ -1,12 +1,12 @@ package com.jnape.palatable.lambda.monoid.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; import com.jnape.palatable.lambda.monoid.Monoid; import com.jnape.palatable.lambda.semigroup.Semigroup; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monoid.Monoid.monoid; /** diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java index 5ae09b8ac..b46ff9612 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java @@ -1,7 +1,7 @@ package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; import com.jnape.palatable.lambda.semigroup.Semigroup; diff --git a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java similarity index 97% rename from src/test/java/com/jnape/palatable/lambda/functions/IOTest.java rename to src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 578f458f3..193c966d2 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -1,6 +1,8 @@ -package com.jnape.palatable.lambda.functions; +package com.jnape.palatable.lambda.io; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -16,8 +18,8 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.IO.externallyManaged; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.externallyManaged; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java index 782ee334f..c0e9f6d17 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.monoid.Monoid; import org.junit.Test; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monoid.builtin.RunAll.runAll; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java index c8840da69..329fe8429 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java @@ -3,7 +3,7 @@ import com.jnape.palatable.lambda.semigroup.Semigroup; import org.junit.Test; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.semigroup.builtin.RunAll.runAll; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/testsupport/EqualityAwareIO.java b/src/test/java/testsupport/EqualityAwareIO.java index b662f968d..1a82def86 100644 --- a/src/test/java/testsupport/EqualityAwareIO.java +++ b/src/test/java/testsupport/EqualityAwareIO.java @@ -1,12 +1,12 @@ package testsupport; -import com.jnape.palatable.lambda.functions.IO; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; import java.util.function.Function; -import static com.jnape.palatable.lambda.functions.IO.io; +import static com.jnape.palatable.lambda.io.IO.io; import static java.util.Objects.hash; public final class EqualityAwareIO implements Monad> { From 05356aa8a872b20ea3906b757ee181499748e7fe Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 31 Mar 2019 17:03:54 -0500 Subject: [PATCH 114/348] Adding Lazy, a monad representing a lazy computation --- CHANGELOG.md | 3 + .../lambda/functor/builtin/Lazy.java | 153 ++++++++++++++++++ .../lambda/functor/builtin/LazyTest.java | 52 ++++++ .../com/jnape/palatable/lambda/io/IOTest.java | 24 ++- src/test/java/testsupport/Constants.java | 8 + 5 files changed, 227 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java create mode 100644 src/test/java/testsupport/Constants.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 40a692490..04d86f6a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ factory methods should continue to work (by simply targeting `Supplier` now inst might need to be reworked, and subtyping is obviously no longer supported. - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively +### Added +- `Lazy`, a monad supporting stack-safe lazy evaluation + ## [3.3.0] - 2019-02-18 ### Added - `MergeMaps`, a `Monoid` on `Map` formed by `Map#merge` diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java new file mode 100644 index 000000000..3e61d3d29 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java @@ -0,0 +1,153 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.LinkedList; +import java.util.function.Function; +import java.util.function.Supplier; + +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +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; + +/** + * A {@link Monad} representing a lazily-computed value. Stack-safe. + * + * @param the value type + */ +public abstract class Lazy implements Monad> { + + private Lazy() { + } + + /** + * Returns the value represented by this lazy computation. + * + * @return the value + */ + public abstract A value(); + + /** + * {@inheritDoc} + */ + @Override + public Lazy flatMap(Function>> f) { + @SuppressWarnings("unchecked") Lazy source = (Lazy) this; + @SuppressWarnings({"unchecked", "RedundantCast"}) + Function> flatMap = (Function>) (Object) f; + return new Compose<>(source, flatMap); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy pure(B b) { + return lazy(b); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy fmap(Function fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy zip(Applicative, Lazy> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } + + /** + * Lift a pure value into a lazy computation. + * + * @param value the value + * @param the value type + * @return the new {@link Lazy} + */ + public static Lazy lazy(A value) { + return lazy(() -> value); + } + + /** + * Wrap a computation in a lazy computation. + * + * @param supplier the computation + * @param the value type + * @return the new {@link Lazy} + */ + public static Lazy lazy(Supplier supplier) { + return new Val<>(fn0(supplier)); + } + + private static final class Val extends Lazy { + private final Fn0 fn0; + + private Val(Fn0 fn0) { + this.fn0 = fn0; + } + + @Override + public A value() { + return fn0.apply(); + } + } + + private static final class Compose extends Lazy { + private final Lazy source; + private final Function> flatMap; + + private Compose(Lazy source, + Function> flatMap) { + this.source = source; + this.flatMap = flatMap; + } + + @Override + public A value() { + @SuppressWarnings("unchecked") Tuple2, LinkedList>>> tuple = + tuple((Lazy) this, new LinkedList<>()); + @SuppressWarnings("unchecked") + A a = (A) trampoline(into((source, flatMaps) -> { + if (source instanceof Compose) { + Compose nested = (Compose) source; + flatMaps.push(nested.flatMap); + return recurse(tuple(nested.source, flatMaps)); + } + + if (flatMaps.isEmpty()) + return terminate(source.value()); + + return recurse(tuple(flatMaps.pop().apply(source.value()), flatMaps)); + }), tuple); + + return a; + } + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java new file mode 100644 index 000000000..f8f80e2d9 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java @@ -0,0 +1,52 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; + +public class LazyTest { + + @Test + public void valueExtraction() { + assertEquals("foo", lazy("foo").value()); + assertEquals("foo", lazy(() -> "foo").value()); + } + + @Test + public void lazyEvaluation() { + AtomicBoolean invoked = new AtomicBoolean(false); + Lazy lazy = lazy(0).flatMap(x -> { + invoked.set(true); + return lazy(x + 1); + }); + assertFalse(invoked.get()); + assertEquals((Integer) 1, lazy.value()); + assertTrue(invoked.get()); + } + + @Test + public void linearStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), lazy(0)).value()); + } + + @Test + public void recursiveStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + new Function, Lazy>() { + @Override + public Lazy apply(Lazy lazy) { + return lazy.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(lazy(x + 1)) : lazy(x)); + } + }.apply(lazy(0)) + .value()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 193c966d2..af584a03b 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -2,7 +2,6 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -18,21 +17,20 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.io.IO.externallyManaged; -import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; +import static com.jnape.palatable.lambda.io.IO.externallyManaged; +import static com.jnape.palatable.lambda.io.IO.io; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.Executors.newFixedThreadPool; import static java.util.concurrent.ForkJoinPool.commonPool; import static org.junit.Assert.assertEquals; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; @RunWith(Traits.class) public class IOTest { - private static final int STACK_EXPLODING_NUMBER = 50_000; - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) public EqualityAwareIO testSubject() { return new EqualityAwareIO<>(io(1)); @@ -125,9 +123,9 @@ public void exceptionallyRescuesFutures() { @Test public void linearSyncStackSafety() { - assertEquals((Integer) STACK_EXPLODING_NUMBER, + assertEquals(STACK_EXPLODING_NUMBER, times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), io(0)).unsafePerformIO()); - assertEquals((Integer) STACK_EXPLODING_NUMBER, + assertEquals(STACK_EXPLODING_NUMBER, times(STACK_EXPLODING_NUMBER, f -> f.zip(f.pure(x -> x + 1)), io(0)).unsafePerformIO()); assertEquals((Integer) 0, times(STACK_EXPLODING_NUMBER, f -> f.pure(0).discardR(f), io(0)).unsafePerformIO()); @@ -135,13 +133,13 @@ public void linearSyncStackSafety() { times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardR(f), io(0)).unsafePerformIO()); assertEquals((Integer) 0, times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardL(f), io(0)).unsafePerformIO()); - assertEquals((Integer) STACK_EXPLODING_NUMBER, + assertEquals(STACK_EXPLODING_NUMBER, times(STACK_EXPLODING_NUMBER, f -> f.flatMap(x -> f.pure(x + 1)), io(0)).unsafePerformIO()); } @Test public void recursiveSyncFlatMapStackSafety() { - assertEquals((Integer) STACK_EXPLODING_NUMBER, + assertEquals(STACK_EXPLODING_NUMBER, new Fn1, IO>() { @Override public IO apply(IO a) { @@ -153,9 +151,9 @@ public IO apply(IO a) { @Test public void linearAsyncStackSafety() { - assertEquals((Integer) STACK_EXPLODING_NUMBER, + assertEquals(STACK_EXPLODING_NUMBER, times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), io(0)).unsafePerformAsyncIO().join()); - assertEquals((Integer) STACK_EXPLODING_NUMBER, + assertEquals(STACK_EXPLODING_NUMBER, times(STACK_EXPLODING_NUMBER, f -> f.zip(f.pure(x -> x + 1)), io(0)).unsafePerformAsyncIO() .join()); assertEquals((Integer) 0, @@ -164,14 +162,14 @@ public void linearAsyncStackSafety() { times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardR(f), io(0)).unsafePerformAsyncIO().join()); assertEquals((Integer) 0, times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardL(f), io(0)).unsafePerformAsyncIO().join()); - assertEquals((Integer) STACK_EXPLODING_NUMBER, + assertEquals(STACK_EXPLODING_NUMBER, times(STACK_EXPLODING_NUMBER, f -> f.flatMap(x -> f.pure(x + 1)), io(0)).unsafePerformAsyncIO() .join()); } @Test public void recursiveAsyncFlatMapStackSafety() { - assertEquals((Integer) STACK_EXPLODING_NUMBER, + assertEquals(STACK_EXPLODING_NUMBER, new Fn1, IO>() { @Override public IO apply(IO a) { diff --git a/src/test/java/testsupport/Constants.java b/src/test/java/testsupport/Constants.java new file mode 100644 index 000000000..a439920d6 --- /dev/null +++ b/src/test/java/testsupport/Constants.java @@ -0,0 +1,8 @@ +package testsupport; + +public final class Constants { + public static final Integer STACK_EXPLODING_NUMBER = 50_000; + + private Constants() { + } +} From 4e76e97286ec21e1a9a8763b9c647671c8a63fd6 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 9 Apr 2019 22:33:14 -0500 Subject: [PATCH 115/348] Adding LazyRec for modelling lazy, stack-safe recursion --- .gitignore | 3 +- CHANGELOG.md | 1 + .../lambda/functions/builtin/fn2/LazyRec.java | 57 +++++++++++++++ .../lambda/functor/builtin/Lazy.java | 14 ++-- .../palatable/lambda/functions/Fn0Test.java | 21 ------ .../palatable/lambda/functions/Fn1Test.java | 11 +-- .../functions/builtin/fn2/LazyRecTest.java | 37 ++++++++++ .../lambda/functor/builtin/LazyTest.java | 26 +++++-- .../com/jnape/palatable/lambda/io/IOTest.java | 6 +- .../jnape/palatable/lambda/lens/IsoTest.java | 7 +- .../jnape/palatable/lambda/lens/LensTest.java | 12 ++-- .../lambda/semigroup/SemigroupTest.java | 1 - .../java/testsupport/EqualityAwareFn0.java | 72 ------------------- .../java/testsupport/EqualityAwareFn1.java | 55 -------------- .../java/testsupport/EqualityAwareIO.java | 60 ---------------- .../java/testsupport/EqualityAwareIso.java | 72 ------------------- .../java/testsupport/EqualityAwareLens.java | 57 --------------- src/test/java/testsupport/EquatableM.java | 58 +++++++++++++++ 18 files changed, 202 insertions(+), 368 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java delete mode 100644 src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRecTest.java delete mode 100644 src/test/java/testsupport/EqualityAwareFn0.java delete mode 100644 src/test/java/testsupport/EqualityAwareFn1.java delete mode 100644 src/test/java/testsupport/EqualityAwareIO.java delete mode 100644 src/test/java/testsupport/EqualityAwareIso.java delete mode 100644 src/test/java/testsupport/EqualityAwareLens.java create mode 100644 src/test/java/testsupport/EquatableM.java diff --git a/.gitignore b/.gitignore index 3425b85ff..6b65bb21d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea/* target/* -*.iml \ No newline at end of file +*.iml +.java-version \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 04d86f6a0..4e7234879 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ might need to be reworked, and subtyping is obviously no longer supported. ### Added - `Lazy`, a monad supporting stack-safe lazy evaluation +- `LazyRec`, a function for writing stack-safe recursive algorithms embedded in `Lazy` ## [3.3.0] - 2019-02-18 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java new file mode 100644 index 000000000..1e1ffbc8f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java @@ -0,0 +1,57 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.builtin.Lazy; + +import java.util.function.BiFunction; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.Monad.join; + +/** + * Given a {@link BiFunction} that receives a recursive function and an input and yields a {@link Lazy lazy} result, and + * an input, produce a {@link Lazy lazy} result that, when forced, will recursively invoke the function until it + * terminates in a stack-safe way. + *

+ * Example: + *

+ * 
+ * Lazy lazyFactorial = lazyRec((fact, x) -> x.equals(ONE)
+ *                                                               ? lazy(x)
+ *                                                               : fact.apply(x.subtract(ONE)).fmap(y -> y.multiply(x)),
+ *                                                  BigInteger.valueOf(50_000));
+ * BigInteger value = lazyFactorial.value(); // 3.34732050959714483691547609407148647791277322381045 × 10^213236
+ * 
+ * 
+ * + * @param the input type + * @param the output type + */ +public final class LazyRec implements + Fn2>, A, Lazy>, A, Lazy> { + + private static final LazyRec INSTANCE = new LazyRec<>(); + + private LazyRec() { + } + + @Override + public Lazy apply(BiFunction>, A, Lazy> fn, A a) { + return join(lazy(() -> fn.apply(nextA -> apply(fn, nextA), a))); + } + + @SuppressWarnings("unchecked") + public static LazyRec lazyRec() { + return (LazyRec) INSTANCE; + } + + public static Fn1> lazyRec(BiFunction>, A, Lazy> fn) { + return LazyRec.lazyRec().apply(fn); + } + + public static Lazy lazyRec(BiFunction>, A, Lazy> fn, A a) { + return lazyRec(fn).apply(a); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java index 3e61d3d29..f3f4be0ac 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java @@ -48,7 +48,7 @@ public Lazy flatMap(Function>> f) { * {@inheritDoc} */ @Override - public Lazy pure(B b) { + public final Lazy pure(B b) { return lazy(b); } @@ -56,7 +56,7 @@ public Lazy pure(B b) { * {@inheritDoc} */ @Override - public Lazy fmap(Function fn) { + public final Lazy fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } @@ -72,7 +72,7 @@ public Lazy zip(Applicative, Lazy> ap * {@inheritDoc} */ @Override - public Lazy discardL(Applicative> appB) { + public final Lazy discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } @@ -80,7 +80,7 @@ public Lazy discardL(Applicative> appB) { * {@inheritDoc} */ @Override - public Lazy discardR(Applicative> appB) { + public final Lazy discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } @@ -103,13 +103,13 @@ public static Lazy lazy(A value) { * @return the new {@link Lazy} */ public static Lazy lazy(Supplier supplier) { - return new Val<>(fn0(supplier)); + return new Later<>(fn0(supplier)); } - private static final class Val extends Lazy { + private static final class Later extends Lazy { private final Fn0 fn0; - private Val(Fn0 fn0) { + private Later(Fn0 fn0) { this.fn0 = fn0; } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java deleted file mode 100644 index d04084205..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.jnape.palatable.lambda.functions; - -import com.jnape.palatable.traitor.annotations.TestTraits; -import com.jnape.palatable.traitor.runners.Traits; -import org.junit.runner.RunWith; -import testsupport.EqualityAwareFn0; -import testsupport.traits.ApplicativeLaws; -import testsupport.traits.FunctorLaws; -import testsupport.traits.MonadLaws; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; - -@RunWith(Traits.class) -public class Fn0Test { - - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public Fn0 testSubject() { - return new EqualityAwareFn0<>(constantly(1).thunk(UNIT)); - } -} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index bd3237f2c..20074539b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -4,7 +4,7 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EqualityAwareFn1; +import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -13,6 +13,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn1.fn1; import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; @@ -21,8 +22,8 @@ public class Fn1Test { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public Fn1 testSubject() { - return new EqualityAwareFn1<>("1", Integer::parseInt); + public EquatableM, ?> testSubject() { + return new EquatableM<>(fn1(Integer::parseInt), f -> f.apply("1")); } @Test @@ -35,9 +36,9 @@ public void profunctorProperties() { } @Test - public void fn1() { + public void staticFactoryMethods() { Function parseInt = Integer::parseInt; - assertEquals((Integer) 1, Fn1.fn1(parseInt).apply("1")); + assertEquals((Integer) 1, fn1(parseInt).apply("1")); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRecTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRecTest.java new file mode 100644 index 000000000..8987fe32a --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRecTest.java @@ -0,0 +1,37 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.LazyRec.lazyRec; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; + +public class LazyRecTest { + + @Test + public void recursivelyComputesValue() { + assertEquals(STACK_EXPLODING_NUMBER, + LazyRec.lazyRec((f, x) -> x < STACK_EXPLODING_NUMBER + ? f.apply(x + 1) + : lazy(x), + 0) + .value()); + } + + @Test + public void defersAllComputationUntilForced() { + AtomicBoolean invoked = new AtomicBoolean(false); + lazyRec((f, x) -> { + invoked.set(true); + return lazy(x); + }, + 0); + + assertFalse(invoked.get()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java index f8f80e2d9..c506f357c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java @@ -1,9 +1,16 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -12,8 +19,14 @@ import static org.junit.Assert.assertTrue; import static testsupport.Constants.STACK_EXPLODING_NUMBER; +@RunWith(Traits.class) public class LazyTest { + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public EquatableM, Integer> testSubject() { + return new EquatableM<>(lazy(0), Lazy::value); + } + @Test public void valueExtraction() { assertEquals("foo", lazy("foo").value()); @@ -41,12 +54,13 @@ public void linearStackSafety() { @Test public void recursiveStackSafety() { assertEquals(STACK_EXPLODING_NUMBER, - new Function, Lazy>() { + new Fn1, Lazy>() { @Override - public Lazy apply(Lazy lazy) { - return lazy.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(lazy(x + 1)) : lazy(x)); + public Lazy apply(Lazy lazyX) { + return lazyX.flatMap(x -> x < STACK_EXPLODING_NUMBER + ? apply(lazy(x + 1)) + : lazy(x)); } - }.apply(lazy(0)) - .value()); + }.apply(lazy(0)).value()); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index af584a03b..0c9ba0535 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -6,7 +6,7 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EqualityAwareIO; +import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -32,8 +32,8 @@ public class IOTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EqualityAwareIO testSubject() { - return new EqualityAwareIO<>(io(1)); + public EquatableM, Integer> testSubject() { + return new EquatableM<>(io(1), IO::unsafePerformIO); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java b/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java index 016de15ee..003c7bda7 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java +++ b/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java @@ -1,11 +1,12 @@ package com.jnape.palatable.lambda.lens; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.builtin.Const; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EqualityAwareIso; +import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -27,8 +28,8 @@ public class IsoTest { iso(Integer::parseInt, dbl -> dbl.toString().chars().mapToObj(x -> (char) x).collect(toList())); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public Iso, Integer, Double> testSubject() { - return new EqualityAwareIso<>("123", 1.23d, ISO); + public EquatableM, ?> testSubject() { + return new EquatableM<>(ISO, iso -> iso.apply(Const::new, "123")); } @Test 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 12d94b30c..f5478be8f 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java @@ -8,7 +8,7 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EqualityAwareLens; +import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -35,12 +35,14 @@ @RunWith(Traits.class) public class LensTest { - private static final Lens>, Map>, List, Set> EARLIER_LENS = lens(m -> m.get("foo"), (m, s) -> singletonMap("foo", s)); - private static final Lens, Set, String, Integer> LENS = lens(xs -> xs.get(0), (xs, i) -> singleton(i)); + private static final Lens>, Map>, List, Set> + EARLIER_LENS = lens(m -> m.get("foo"), (m, s) -> singletonMap("foo", s)); + private static final Lens, Set, String, Integer> + LENS = lens(xs -> xs.get(0), (xs, i) -> singleton(i)); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public Lens, List, Integer, String> testSubject() { - return new EqualityAwareLens<>(emptyMap(), lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s)))); + public EquatableM, ?, Integer, String, Lens>, ?> testSubject() { + return new EquatableM<>(lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s))), l -> view(l, emptyMap())); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java index 94697cda3..ec20057bc 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java @@ -1,6 +1,5 @@ package com.jnape.palatable.lambda.semigroup; -import com.jnape.palatable.lambda.semigroup.Semigroup; import org.junit.Test; import static java.util.Arrays.asList; diff --git a/src/test/java/testsupport/EqualityAwareFn0.java b/src/test/java/testsupport/EqualityAwareFn0.java deleted file mode 100644 index 17b3318d5..000000000 --- a/src/test/java/testsupport/EqualityAwareFn0.java +++ /dev/null @@ -1,72 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.functions.Fn0; -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static java.util.Objects.hash; - -public final class EqualityAwareFn0 implements Fn0 { - private final Fn0 fn; - - public EqualityAwareFn0(Fn0 fn) { - this.fn = fn; - } - - @Override - public A apply() { - return fn.apply(); - } - - @Override - public A apply(Unit unit) { - return apply(); - } - - @Override - public EqualityAwareFn0 flatMap(Function>> f) { - return new EqualityAwareFn0<>(fn.flatMap(f)); - } - - @Override - public EqualityAwareFn0 fmap(Function f) { - return new EqualityAwareFn0<>(fn.fmap(f)); - } - - @Override - public EqualityAwareFn0 zip(Applicative, Fn1> appFn) { - return new EqualityAwareFn0<>(fn.zip(appFn)); - } - - @Override - public EqualityAwareFn0 pure(B b) { - return new EqualityAwareFn0<>(fn.pure(b)); - } - - - @Override - public EqualityAwareFn0 discardL(Applicative> appB) { - return new EqualityAwareFn0<>(fn.discardL(appB)); - } - - @Override - public EqualityAwareFn0 discardR(Applicative> appB) { - return new EqualityAwareFn0<>(fn.discardR(appB)); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - return other instanceof Fn0 && ((Fn0) other).apply(UNIT).equals(apply(UNIT)); - } - - @Override - public int hashCode() { - return hash(fn); - } -} diff --git a/src/test/java/testsupport/EqualityAwareFn1.java b/src/test/java/testsupport/EqualityAwareFn1.java deleted file mode 100644 index 464962d19..000000000 --- a/src/test/java/testsupport/EqualityAwareFn1.java +++ /dev/null @@ -1,55 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -import static java.util.Objects.hash; - -public final class EqualityAwareFn1 implements Fn1 { - private final A a; - private final Fn1 fn; - - public EqualityAwareFn1(A a, Fn1 fn) { - this.a = a; - this.fn = fn; - } - - @Override - public B apply(A a) { - return fn.apply(a); - } - - @Override - public EqualityAwareFn1 flatMap(Function>> f) { - return new EqualityAwareFn1<>(a, fn.flatMap(f)); - } - - @Override - public EqualityAwareFn1 fmap(Function f) { - return new EqualityAwareFn1<>(a, fn.fmap(f)); - } - - @Override - public EqualityAwareFn1 zip(Applicative, Fn1> appFn) { - return new EqualityAwareFn1<>(a, fn.zip(appFn)); - } - - @Override - public EqualityAwareFn1 pure(C c) { - return new EqualityAwareFn1<>(a, fn.pure(c)); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - return other instanceof Fn1 && ((Fn1) other).apply(a).equals(apply(a)); - } - - @Override - public int hashCode() { - return hash(a, fn); - } -} diff --git a/src/test/java/testsupport/EqualityAwareIO.java b/src/test/java/testsupport/EqualityAwareIO.java deleted file mode 100644 index 1a82def86..000000000 --- a/src/test/java/testsupport/EqualityAwareIO.java +++ /dev/null @@ -1,60 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.io.IO; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -import static com.jnape.palatable.lambda.io.IO.io; -import static java.util.Objects.hash; - -public final class EqualityAwareIO implements Monad> { - private final IO io; - - public EqualityAwareIO(IO io) { - this.io = io; - } - - @Override - public EqualityAwareIO flatMap(Function>> f) { - return new EqualityAwareIO<>(io.flatMap(f.andThen(x -> x.>coerce().io))); - } - - @Override - public EqualityAwareIO pure(B b) { - return new EqualityAwareIO<>(io(b)); - } - - @Override - public EqualityAwareIO fmap(Function fn) { - return new EqualityAwareIO<>(io.fmap(fn)); - } - - @Override - public EqualityAwareIO zip(Applicative, EqualityAwareIO> appFn) { - return new EqualityAwareIO<>(io.zip(appFn.>>coerce().io)); - } - - @Override - public EqualityAwareIO discardL(Applicative> appB) { - return new EqualityAwareIO<>(io.discardL(appB.>coerce().io)); - } - - @Override - public EqualityAwareIO discardR(Applicative> appB) { - return new EqualityAwareIO<>(io.discardR(appB.>coerce().io)); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - return other instanceof EqualityAwareIO - && ((EqualityAwareIO) other).io.unsafePerformIO().equals(io.unsafePerformIO()); - } - - @Override - public int hashCode() { - return hash(io); - } -} diff --git a/src/test/java/testsupport/EqualityAwareIso.java b/src/test/java/testsupport/EqualityAwareIso.java deleted file mode 100644 index 0efc7f039..000000000 --- a/src/test/java/testsupport/EqualityAwareIso.java +++ /dev/null @@ -1,72 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.LensLike; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.Objects; -import java.util.function.Function; - -import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; -import static com.jnape.palatable.lambda.lens.functions.View.view; - -public final class EqualityAwareIso implements Iso { - private final S s; - private final B b; - private final Iso iso; - - public EqualityAwareIso(S s, B b, Iso iso) { - this.s = s; - this.b = b; - this.iso = iso; - } - - @Override - public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { - return iso.apply(pafb); - } - - @Override - public , FB extends Functor> FT apply( - Function fn, S s) { - return iso.apply(fn, s); - } - - @Override - public EqualityAwareIso fmap(Function fn) { - return new EqualityAwareIso<>(s, b, iso.fmap(fn)); - } - - @Override - public EqualityAwareIso pure(U u) { - return new EqualityAwareIso<>(s, b, iso.pure(u)); - } - - @Override - public EqualityAwareIso zip( - Applicative, LensLike> appFn) { - return new EqualityAwareIso<>(s, b, iso.zip(appFn)); - } - - @Override - public EqualityAwareIso flatMap( - Function>> fn) { - return new EqualityAwareIso<>(s, b, iso.flatMap(fn)); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - if (other instanceof EqualityAwareIso) { - Iso that = (EqualityAwareIso) other; - Boolean sameForward = both(view(this), view(that)).apply(s).into(Objects::equals); - Boolean sameReverse = both(view(this.mirror()), view(that.mirror())).apply(b).into(Objects::equals); - return sameForward && sameReverse; - } - return false; - } -} diff --git a/src/test/java/testsupport/EqualityAwareLens.java b/src/test/java/testsupport/EqualityAwareLens.java deleted file mode 100644 index e8a8cb52f..000000000 --- a/src/test/java/testsupport/EqualityAwareLens.java +++ /dev/null @@ -1,57 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.builtin.Const; -import com.jnape.palatable.lambda.lens.Lens; -import com.jnape.palatable.lambda.lens.LensLike; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.Objects; -import java.util.function.Function; - -public final class EqualityAwareLens implements Lens { - private final S s; - private final Lens lens; - - public EqualityAwareLens(S s, Lens lens) { - this.s = s; - this.lens = lens; - } - - @Override - public , FB extends Functor> FT apply( - Function fn, S s) { - return lens.apply(fn, s); - } - - @Override - public EqualityAwareLens flatMap( - Function>> f) { - return new EqualityAwareLens<>(s, lens.flatMap(f)); - } - - @Override - public EqualityAwareLens fmap(Function fn) { - return new EqualityAwareLens<>(s, lens.fmap(fn)); - } - - @Override - public EqualityAwareLens pure(U u) { - return new EqualityAwareLens<>(s, lens.pure(u)); - } - - @Override - public EqualityAwareLens zip( - Applicative, LensLike> appFn) { - return new EqualityAwareLens<>(s, lens.zip(appFn)); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - return other instanceof Lens - && Objects.equals(((Lens) other)., Const, Const>apply(Const::new, s).runConst(), - this., Const, Const>apply(Const::new, s).runConst()); - } -} diff --git a/src/test/java/testsupport/EquatableM.java b/src/test/java/testsupport/EquatableM.java new file mode 100644 index 000000000..2478e5a97 --- /dev/null +++ b/src/test/java/testsupport/EquatableM.java @@ -0,0 +1,58 @@ +package testsupport; + +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.Objects; +import java.util.function.Function; + +public final class EquatableM, A> implements Monad> { + + private final Monad ma; + private final Function equatable; + + public EquatableM(Monad ma, Function equatable) { + this.ma = ma; + this.equatable = equatable; + } + + @Override + public EquatableM flatMap(Function>> f) { + return new EquatableM<>(ma.flatMap(f.andThen(x -> x.>coerce().ma)), equatable); + } + + @Override + public EquatableM pure(B b) { + return new EquatableM<>(ma.pure(b), equatable); + } + + @Override + public EquatableM fmap(Function fn) { + return new EquatableM<>(ma.fmap(fn), equatable); + } + + @Override + public EquatableM zip(Applicative, EquatableM> appFn) { + return new EquatableM<>(ma.zip(appFn.>>coerce().ma), equatable); + } + + @Override + public EquatableM discardL(Applicative> appB) { + return new EquatableM<>(ma.discardL(appB.>coerce().ma), equatable); + } + + @Override + public EquatableM discardR(Applicative> appB) { + return new EquatableM<>(ma.discardR(appB.>coerce().ma), equatable); + } + + @Override + @SuppressWarnings("unchecked") + public boolean equals(Object other) { + if (other instanceof EquatableM) { + EquatableM that = (EquatableM) other; + return Objects.equals(equatable.apply((M) ma), that.equatable.apply((M) that.ma)); + } + return false; + } +} From f076fc8ab26b30844f568e06255e71fc90d9244a Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 13 Apr 2019 17:45:31 -0500 Subject: [PATCH 116/348] - Adding Applicative#lazyZip, supporting short-circuiting for some types - FoldRight now operates in terms of Lazy and can be short-circuited --- CHANGELOG.md | 2 + .../jnape/palatable/lambda/adt/Either.java | 42 ++++++++++++++ .../com/jnape/palatable/lambda/adt/Maybe.java | 36 ++++++++++++ .../com/jnape/palatable/lambda/adt/These.java | 8 +++ .../com/jnape/palatable/lambda/adt/Try.java | 38 +++++++++++++ .../palatable/lambda/adt/choice/Choice2.java | 51 ++++++++++++++++- .../palatable/lambda/adt/choice/Choice3.java | 52 ++++++++++++++++- .../palatable/lambda/adt/choice/Choice4.java | 50 ++++++++++++++++- .../palatable/lambda/adt/choice/Choice5.java | 54 +++++++++++++++++- .../palatable/lambda/adt/choice/Choice6.java | 55 +++++++++++++++++- .../palatable/lambda/adt/choice/Choice7.java | 56 ++++++++++++++++++- .../palatable/lambda/adt/choice/Choice8.java | 54 +++++++++++++++++- .../lambda/adt/hlist/SingletonHList.java | 9 ++- .../palatable/lambda/adt/hlist/Tuple2.java | 7 +++ .../palatable/lambda/adt/hlist/Tuple3.java | 7 +++ .../palatable/lambda/adt/hlist/Tuple4.java | 7 +++ .../palatable/lambda/adt/hlist/Tuple5.java | 7 +++ .../palatable/lambda/adt/hlist/Tuple6.java | 7 +++ .../palatable/lambda/adt/hlist/Tuple7.java | 7 +++ .../palatable/lambda/adt/hlist/Tuple8.java | 7 +++ .../jnape/palatable/lambda/functions/Fn1.java | 18 +++++- .../jnape/palatable/lambda/functions/Fn2.java | 15 +++++ .../functions/builtin/fn3/FoldRight.java | 53 +++++++++++++----- .../palatable/lambda/functor/Applicative.java | 18 ++++++ .../lambda/functor/builtin/Compose.java | 24 ++++++++ .../lambda/functor/builtin/Const.java | 43 ++++++++------ .../lambda/functor/builtin/Identity.java | 24 ++++++++ .../com/jnape/palatable/lambda/io/IO.java | 9 +++ .../jnape/palatable/lambda/monad/Monad.java | 9 +++ .../jnape/palatable/lambda/monoid/Monoid.java | 6 +- .../palatable/lambda/semigroup/Semigroup.java | 7 ++- .../lambda/traversable/LambdaIterable.java | 51 ++++++++++++++--- .../palatable/lambda/adt/EitherTest.java | 9 +++ .../jnape/palatable/lambda/adt/MaybeTest.java | 9 +++ .../jnape/palatable/lambda/adt/TheseTest.java | 14 +++++ .../jnape/palatable/lambda/adt/TryTest.java | 10 ++++ .../lambda/adt/choice/Choice2Test.java | 9 +++ .../lambda/adt/choice/Choice3Test.java | 12 ++++ .../lambda/adt/choice/Choice4Test.java | 15 +++++ .../lambda/adt/choice/Choice5Test.java | 18 ++++++ .../lambda/adt/choice/Choice6Test.java | 21 +++++++ .../lambda/adt/choice/Choice7Test.java | 24 ++++++++ .../lambda/adt/choice/Choice8Test.java | 27 +++++++++ .../functions/builtin/fn3/FoldRightTest.java | 24 ++++++-- .../lambda/iteration/ConsingIteratorTest.java | 8 ++- .../lambda/semigroup/SemigroupTest.java | 2 +- .../traversable/LambdaIterableTest.java | 41 +++++++++++++- .../testsupport/traits/ApplicativeLaws.java | 35 +++++++----- 48 files changed, 1028 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e7234879..c028d0d3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - ***Breaking Change***: `IO` is now sealed and moved to its own package. Most previous constructions using the static factory methods should continue to work (by simply targeting `Supplier` now instead of an anonymous `IO`), but some might need to be reworked, and subtyping is obviously no longer supported. +- ***Breaking Change***: `FoldRight` now requires `Lazy` as part of its interface to support short-circuiting operations - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ### Added - `Lazy`, a monad supporting stack-safe lazy evaluation - `LazyRec`, a function for writing stack-safe recursive algorithms embedded in `Lazy` +- `Applicative#lazyZip`, for zipping two applicatives in a way that might not require evaluation of one applicative ## [3.3.0] - 2019-02-18 ### Added 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 00f3bf787..c90ee9dd8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -9,6 +9,7 @@ import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -20,6 +21,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Arrays.asList; /** @@ -187,54 +189,94 @@ public Either peek(Consumer leftConsumer, Consumer rightConsumer) { @Override public abstract V match(Function leftFn, Function rightFn); + /** + * {@inheritDoc} + */ @Override public Choice3 diverge() { return match(Choice3::a, Choice3::b); } + /** + * {@inheritDoc} + */ @Override public final Either fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public final Either biMapL(Function fn) { return (Either) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public final Either biMapR(Function fn) { return (Either) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public final Either biMap(Function leftFn, Function rightFn) { return match(l -> left(leftFn.apply(l)), r -> right(rightFn.apply(r))); } + /** + * {@inheritDoc} + */ @Override public final Either pure(R2 r2) { return right(r2); } + /** + * {@inheritDoc} + */ @Override public final Either zip(Applicative, Either> appFn) { return appFn.>>coerce().flatMap(this::biMapR); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Either>> lazyAppFn) { + return match(l -> lazy(left(l)), + r -> lazyAppFn.fmap(eitherLF -> eitherLF.fmap(f -> f.apply(r)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public final Either discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public final Either discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public final >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index ad0b81ad9..7d07ba4c5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -9,6 +9,7 @@ import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -22,6 +23,7 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * The optional type, representing a potentially absent value. This is lambda's analog of {@link Optional}, supporting @@ -125,36 +127,70 @@ public final Maybe fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override public final Maybe zip(Applicative, Maybe> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * Terminate early if this is a {@link Nothing}; otherwise, continue the {@link Applicative#zip zip}. + * + * @param lazyAppFn the lazy other applicative instance + * @param the result type + * @return the zipped {@link Maybe} + */ + @Override + public Lazy> lazyZip(Lazy, Maybe>> lazyAppFn) { + return match(constantly(lazy(nothing())), + a -> lazyAppFn.fmap(maybeF -> maybeF.fmap(f -> f.apply(a)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public final Maybe discardL(Applicative appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public final Maybe discardR(Applicative appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public final Maybe flatMap(Function> f) { return match(constantly(nothing()), f.andThen(Applicative::coerce)); } + /** + * {@inheritDoc} + */ @Override public Choice3 diverge() { return match(Choice3::a, Choice3::b); } + /** + * {@inheritDoc} + */ @Override public Tuple2, Maybe> project() { return CoProduct2.super.project().into(HList::tuple); } + /** + * {@inheritDoc} + */ @Override public Choice2 invert() { return match(Choice2::b, Choice2::a); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index f4ffc5846..494dbb38e 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -14,6 +15,7 @@ import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * The coproduct of a coproduct ({@link CoProduct2}<A, B>) and its product ({@link @@ -96,6 +98,12 @@ public final These zip(Applicative, T return Monad.super.zip(appFn).coerce(); } + @Override + public Lazy> lazyZip(Lazy, These>> lazyAppFn) { + return projectA().>>fmap(a -> lazy(a(a))) + .orElseGet(() -> Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce)); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index d629a967b..5c67e7ebd 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.BoundedBifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -18,6 +19,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek2.peek2; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * A {@link Monad} of the evaluation outcome of an expression that might throw. Try/catch/finally semantics map to @@ -139,36 +141,63 @@ public final Either toEither(Function fn) { return match(fn.andThen(Either::left), Either::right); } + /** + * {@inheritDoc} + */ @Override public Try fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override public Try flatMap(Function>> f) { return match(Try::failure, a -> f.apply(a).coerce()); } + /** + * {@inheritDoc} + */ @Override public Try pure(B b) { return success(b); } + /** + * {@inheritDoc} + */ @Override public Try zip(Applicative, Try> appFn) { return Monad.super.zip(appFn).coerce(); } + @Override + public Lazy> lazyZip(Lazy, Try>> lazyAppFn) { + return match(f -> lazy(failure(f)), + s -> lazyAppFn.fmap(tryF -> tryF.fmap(f -> f.apply(s)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Try discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Try discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( @@ -177,17 +206,26 @@ public Try discardR(Applicative> appB) { a -> fn.apply(a).fmap(Try::success).fmap(Applicative::coerce).coerce()); } + /** + * {@inheritDoc} + */ @Override public Try biMap(Function lFn, Function rFn) { return match(t -> failure(lFn.apply(t)), a -> success(rFn.apply(a))); } + /** + * {@inheritDoc} + */ @Override public Try biMapL(Function fn) { return (Try) BoundedBifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override public Try biMapR(Function fn) { return (Try) BoundedBifunctor.super.biMapR(fn); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index 969da832d..5efb2c09a 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -14,6 +15,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct2}. Unlike {@link Either}, there is no concept of "success" or @@ -43,65 +45,110 @@ public Tuple2, Maybe> project() { return into(HList::tuple, CoProduct2.super.project()); } + /** + * {@inheritDoc} + */ @Override public final Choice3 diverge() { return match(Choice3::a, Choice3::b); } + /** + * {@inheritDoc} + */ @Override public Choice2 invert() { return match(Choice2::b, Choice2::a); } + /** + * {@inheritDoc} + */ @Override public final Choice2 fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public final Choice2 biMapL(Function fn) { return (Choice2) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public final Choice2 biMapR(Function fn) { return (Choice2) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public final Choice2 biMap(Function lFn, Function rFn) { return match(a -> a(lFn.apply(a)), b -> b(rFn.apply(b))); } + /** + * {@inheritDoc} + */ @Override public Choice2 pure(C c) { return b(c); } + /** + * {@inheritDoc} + */ @Override public Choice2 zip(Applicative, Choice2> appFn) { - return appFn.>>coerce() - .match(Choice2::a, this::biMapR); + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy>> lazyZip( + Lazy, Choice2>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(b)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice2 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice2 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public final Choice2 flatMap(Function>> f) { return match(Choice2::a, b -> f.apply(b).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 1f8aa3226..d8f984cf7 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple3; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -14,6 +15,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into3.into3; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct3}. @@ -43,65 +45,111 @@ public Tuple3, Maybe, Maybe> project() { return into3(HList::tuple, CoProduct3.super.project()); } + /** + * {@inheritDoc} + */ @Override public final Choice4 diverge() { return match(Choice4::a, Choice4::b, Choice4::c); } + /** + * {@inheritDoc} + */ @Override public final Choice2 converge(Function> convergenceFn) { return match(Choice2::a, Choice2::b, convergenceFn.andThen(cp2 -> cp2.match(Choice2::a, Choice2::b))); } + /** + * {@inheritDoc} + */ @Override public final Choice3 fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public final Choice3 biMapL(Function fn) { return (Choice3) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public final Choice3 biMapR(Function fn) { return (Choice3) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public final Choice3 biMap(Function lFn, Function rFn) { return match(Choice3::a, b -> b(lFn.apply(b)), c -> c(rFn.apply(c))); } + /** + * {@inheritDoc} + */ @Override public Choice3 pure(D d) { return c(d); } + /** + * {@inheritDoc} + */ @Override public Choice3 zip(Applicative, Choice3> appFn) { - return appFn.>>coerce() - .match(Choice3::a, Choice3::b, this::biMapR); + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice3>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(c)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice3 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice3 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice3 flatMap(Function>> f) { return match(Choice3::a, Choice3::b, c -> f.apply(c).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index 494638330..0e9a0aebb 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple4; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -14,6 +15,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into4.into4; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct4}. @@ -44,11 +46,17 @@ public Tuple4, Maybe, Maybe, Maybe> project() { return into4(HList::tuple, CoProduct4.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice5 diverge() { return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d); } + /** + * {@inheritDoc} + */ @Override public Choice3 converge(Function> convergenceFn) { return match(Choice3::a, @@ -57,17 +65,26 @@ public Choice3 converge(Function cp3.match(Choice3::a, Choice3::b, Choice3::c))); } + /** + * {@inheritDoc} + */ @Override public final Choice4 fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public final Choice4 biMapL(Function fn) { return (Choice4) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public final Choice4 biMapR(Function fn) { @@ -80,32 +97,61 @@ public final Choice4 biMap(Function l return match(Choice4::a, Choice4::b, c -> c(lFn.apply(c)), d -> d(rFn.apply(d))); } + /** + * {@inheritDoc} + */ @Override public Choice4 pure(E e) { return d(e); } + /** + * {@inheritDoc} + */ @Override public Choice4 zip(Applicative, Choice4> appFn) { - return appFn.>>coerce() - .match(Choice4::a, Choice4::b, Choice4::c, this::biMapR); + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice4>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(d)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice4 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice4 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice4 flatMap(Function>> f) { return match(Choice4::a, Choice4::b, Choice4::c, d -> f.apply(d).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index 5954d4ae2..ab7a8c2fb 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple5; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -14,6 +15,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into5.into5; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct5}. @@ -45,11 +47,17 @@ public Tuple5, Maybe, Maybe, Maybe, Maybe> project() { return into5(HList::tuple, CoProduct5.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice6 diverge() { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e); } + /** + * {@inheritDoc} + */ @Override public Choice4 converge(Function> convergenceFn) { return match(Choice4::a, @@ -59,55 +67,97 @@ public Choice4 converge(Function cp4.match(Choice4::a, Choice4::b, Choice4::c, Choice4::d))); } + /** + * {@inheritDoc} + */ @Override public Choice5 fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Choice5 biMapL(Function fn) { return (Choice5) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Choice5 biMapR(Function fn) { return (Choice5) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public Choice5 biMap(Function lFn, Function rFn) { return match(Choice5::a, Choice5::b, Choice5::c, d -> d(lFn.apply(d)), e -> e(rFn.apply(e))); } + /** + * {@inheritDoc} + */ @Override public Choice5 pure(F f) { return e(f); } + /** + * {@inheritDoc} + */ @Override public Choice5 zip(Applicative, Choice5> appFn) { - return appFn.>>coerce() - .match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, this::biMapR); + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice5>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazy(d(d)), + e -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(e)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice5 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice5 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice5 flatMap(Function>> f) { return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, e -> f.apply(e).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index 8076383b8..59df7eee1 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple6; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -14,6 +15,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into6.into6; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct6}. @@ -46,11 +48,17 @@ public Tuple6, Maybe, Maybe, Maybe, Maybe, Maybe> projec return into6(HList::tuple, CoProduct6.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice7 diverge() { return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f); } + /** + * {@inheritDoc} + */ @Override public Choice5 converge(Function> convergenceFn) { return match(Choice5::a, @@ -61,57 +69,100 @@ public Choice5 converge(Function cp5.match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, Choice5::e))); } + /** + * {@inheritDoc} + */ @Override public Choice6 fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Choice6 biMapL(Function fn) { return (Choice6) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Choice6 biMapR(Function fn) { return (Choice6) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public Choice6 biMap(Function lFn, Function rFn) { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, e -> e(lFn.apply(e)), f -> f(rFn.apply(f))); } + /** + * {@inheritDoc} + */ @Override public Choice6 pure(G g) { return f(g); } + /** + * {@inheritDoc} + */ @Override public Choice6 zip( Applicative, Choice6> appFn) { - return appFn.>>coerce() - .match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, this::biMapR); + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice6>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazy(d(d)), + e -> lazy(e(e)), + f -> lazyAppFn.fmap(choiceFn -> choiceFn.fmap(fn -> fn.apply(f)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice6 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice6 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice6 flatMap( Function>> fn) { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, f -> fn.apply(f).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index bd7f3b65f..a5f170e4b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple7; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -14,6 +15,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into7.into7; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct7}. @@ -47,11 +49,17 @@ public Tuple7, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe< return into7(HList::tuple, CoProduct7.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice8 diverge() { return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, Choice8::g); } + /** + * {@inheritDoc} + */ @Override public Choice6 converge( Function> convergenceFn) { @@ -64,57 +72,101 @@ public Choice6 converge( convergenceFn.andThen(cp6 -> cp6.match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, Choice6::f))); } + /** + * {@inheritDoc} + */ @Override public Choice7 fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Choice7 biMapL(Function fn) { return (Choice7) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Choice7 biMapR(Function fn) { return (Choice7) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public Choice7 biMap(Function lFn, Function rFn) { return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, f -> f(lFn.apply(f)), g -> g(rFn.apply(g))); } + /** + * {@inheritDoc} + */ @Override public Choice7 pure(H h) { return g(h); } + /** + * {@inheritDoc} + */ @Override public Choice7 zip( Applicative, Choice7> appFn) { - return appFn.>>coerce() - .match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, this::biMapR); + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice7>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazy(d(d)), + e -> lazy(e(e)), + f -> lazy(f(f)), + g -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(g)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice7 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice7 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice7 flatMap( Function>> fn) { return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, g -> fn.apply(g).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index 9755c5050..3cd03e2a9 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple8; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -14,6 +15,7 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into8.into8; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Canonical ADT representation of {@link CoProduct8}. @@ -47,6 +49,9 @@ public Tuple8, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe< return into8(HList::tuple, CoProduct8.super.project()); } + /** + * {@inheritDoc} + */ @Override public Choice7 converge( Function> convergenceFn) { @@ -60,57 +65,102 @@ public Choice7 converge( convergenceFn.andThen(cp7 -> cp7.match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g))); } + /** + * {@inheritDoc} + */ @Override public Choice8 fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Choice8 biMapL(Function fn) { return (Choice8) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Choice8 biMapR(Function fn) { return (Choice8) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public Choice8 biMap(Function lFn, Function rFn) { return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, g -> g(lFn.apply(g)), h -> h(rFn.apply(h))); } + /** + * {@inheritDoc} + */ @Override public Choice8 pure(I i) { return h(i); } + /** + * {@inheritDoc} + */ @Override public Choice8 zip( Applicative, Choice8> appFn) { - return appFn.>>coerce() - .match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, Choice8::g, this::biMapR); + return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Choice8>> lazyAppFn) { + return match(a -> lazy(a(a)), + b -> lazy(b(b)), + c -> lazy(c(c)), + d -> lazy(d(d)), + e -> lazy(e(e)), + f -> lazy(f(f)), + g -> lazy(g(g)), + h -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(h)).coerce())); + } + + /** + * {@inheritDoc} + */ @Override public Choice8 discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice8 discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Choice8 flatMap( Function>> fn) { return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, Choice8::g, h -> fn.apply(h).coerce()); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index 0a8143d84..0c8608e31 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.hlist.HList.HNil; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -45,6 +46,12 @@ public <_1Prime> SingletonHList<_1Prime> zip( return Monad.super.zip(appFn).coerce(); } + @Override + public <_1Prime> Lazy> lazyZip( + Lazy, SingletonHList>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + @Override public <_1Prime> SingletonHList<_1Prime> discardL(Applicative<_1Prime, SingletonHList> appB) { return Monad.super.discardL(appB).coerce(); @@ -68,7 +75,7 @@ public } /** - * Apply {@link SingletonHList#head} to fn and return the result. + * Apply {@link SingletonHList#head()} to fn and return the result. * * @param fn the function to apply * @param the return type of the function 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 621537198..7268d0595 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 @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -109,6 +110,12 @@ public <_2Prime> Tuple2<_1, _2Prime> zip( return Monad.super.zip(appFn).coerce(); } + @Override + public <_2Prime> Lazy> lazyZip( + Lazy, Tuple2<_1, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + @Override public <_2Prime> Tuple2<_1, _2Prime> discardL(Applicative<_2Prime, Tuple2<_1, ?>> appB) { return Monad.super.discardL(appB).coerce(); 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 32d8a5359..de7116c03 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 @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.product.Product3; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -111,6 +112,12 @@ public <_3Prime> Tuple3<_1, _2, _3Prime> zip( return biMapR(appFn.>>coerce()._3()); } + @Override + public <_3Prime> Lazy> lazyZip( + Lazy, Tuple3<_1, _2, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + @Override public <_3Prime> Tuple3<_1, _2, _3Prime> discardL(Applicative<_3Prime, Tuple3<_1, _2, ?>> appB) { return Monad.super.discardL(appB).coerce(); 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 af141c9f3..b240ab948 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 @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.product.Product4; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -126,6 +127,12 @@ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> zip( return biMapR(appFn.>>coerce()._4()); } + @Override + public <_4Prime> Lazy> lazyZip( + Lazy, Tuple4<_1, _2, _3, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> discardL(Applicative<_4Prime, Tuple4<_1, _2, _3, ?>> appB) { return Monad.super.discardL(appB).coerce(); 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 65dfb3c7a..5c9764aff 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 @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.product.Product5; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -146,6 +147,12 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> zip( return Monad.super.zip(appFn).coerce(); } + @Override + public <_5Prime> Lazy> lazyZip( + Lazy, Tuple5<_1, _2, _3, _4, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> discardL(Applicative<_5Prime, Tuple5<_1, _2, _3, _4, ?>> appB) { return Monad.super.discardL(appB).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 0f3046ace..92b983675 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.product.Product6; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -166,6 +167,12 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> zip( return Monad.super.zip(appFn).coerce(); } + @Override + public <_6Prime> Lazy> lazyZip( + Lazy, Tuple6<_1, _2, _3, _4, _5, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> discardL( Applicative<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>> appB) { diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index 1910381d1..f3f010e2e 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.product.Product7; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -185,6 +186,12 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> zip( return Monad.super.zip(appFn).coerce(); } + @Override + public <_7Prime> Lazy> lazyZip( + Lazy, Tuple7<_1, _2, _3, _4, _5, _6, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> discardL( Applicative<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appB) { diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 30a9eba61..6d424e3bb 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.product.Product8; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -204,6 +205,12 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> zip( return Monad.super.zip(appFn).coerce(); } + @Override + public <_8Prime> Lazy> lazyZip( + Lazy, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> discardL( Applicative<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appB) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index c9fa0ee26..3ea573870 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Strong; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import java.util.function.BiFunction; @@ -50,6 +51,9 @@ default Fn2 widen() { return fn2(constantly(this)); } + /** + * {@inheritDoc} + */ @Override default Fn1 flatMap(Function>> f) { return a -> f.apply(apply(a)).>coerce().apply(a); @@ -80,7 +84,7 @@ default Fn1 pure(C c) { */ @Override default Fn1 zip(Applicative, Fn1> appFn) { - return a -> appFn.>>coerce().apply(a).apply(apply(a)); + return Monad.super.zip(appFn).coerce(); } /** @@ -91,6 +95,14 @@ default Fn1 zip(Fn2 appFn) { return zip((Fn1>) (Object) appFn); } + /** + * {@inheritDoc} + */ + @Override + default Lazy> lazyZip(Lazy, Fn1>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + /** * {@inheritDoc} */ @@ -158,6 +170,10 @@ default Fn1, Tuple2> strengthen() { return t -> t.fmap(this); } + /** + * {@inheritDoc} + */ + @Override default Fn1> carry() { return (Fn1>) Strong.super.carry(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index dd116a80f..1386ae11e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -91,26 +91,41 @@ default BiFunction toBiFunction() { return this::apply; } + /** + * {@inheritDoc} + */ @Override default Fn2 discardR(Applicative> appB) { return fn2(Fn1.super.discardR(appB)); } + /** + * {@inheritDoc} + */ @Override default Fn2 diMapL(Function fn) { return fn2(Fn1.super.diMapL(fn)); } + /** + * {@inheritDoc} + */ @Override default Fn2 contraMap(Function fn) { return fn2(Fn1.super.contraMap(fn)); } + /** + * {@inheritDoc} + */ @Override default Fn3 compose(BiFunction before) { return fn3(Fn1.super.compose(before)); } + /** + * {@inheritDoc} + */ @Override default Fn3 compose(Fn2 before) { return fn3(Fn1.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java index bb6f49f2c..a31648e68 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java @@ -3,18 +3,33 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import java.util.function.BiFunction; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Reverse.reverse; -import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; +import static com.jnape.palatable.lambda.functions.builtin.fn2.LazyRec.lazyRec; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** - * Given an Iterable of As, a starting value B, and a {@link - * BiFunction}<A, B, B>, iteratively accumulate over the Iterable, ultimately returning a - * final B value. If the Iterable is empty, just return the starting B value. - * This function is the iterative inverse of {@link FoldLeft}, such that foldRight(f, 0, asList(1, 2, 3, 4, - * 5)) is evaluated as f(f(f(f(f(0, 5), 4), 3), 2), 1). + * Given an Iterable of As, a starting {@link Lazy lazy} value B, and a + * {@link BiFunction}<A, {@link Lazy}<B>, {@link Lazy}<B>>, iteratively accumulate over + * the Iterable, ultimately returning a final {@link Lazy}<B> value. If the + * Iterable is empty, just return the starting {@link Lazy}<B> value. + * This function is computationally the iterative inverse of {@link FoldLeft}, but uses {@link Lazy} to allow support + * stack-safe execution. + *

+ * Example: + *

+ * 
+ * Lazy> lazyCopy = foldRight(
+ *     (head, lazyTail) -> lazy(cons(head, () -> lazyTail.value().iterator())),
+ *     lazy(emptyList()),
+ *     iterate(x -> x + 1, 0));
+ * Iterable copy = () -> lazyCopy.value().iterator();
+ * take(3, copy).forEach(System.out::println); // prints "1, 2, 3"
+ * take(3, copy).forEach(System.out::println); // prints "1, 2, 3"
+ * 
+ * 
*

* For more information, read about Catamorphisms. @@ -23,32 +38,40 @@ * @param The accumulation type * @see FoldLeft */ -public final class FoldRight implements Fn3, B, Iterable, B> { +public final class FoldRight implements + Fn3, ? extends Lazy>, Lazy, Iterable, Lazy> { - private static final FoldRight INSTANCE = new FoldRight(); + private static final FoldRight INSTANCE = new FoldRight<>(); private FoldRight() { } @Override - public B apply(BiFunction fn, B acc, Iterable as) { - return foldLeft((b, a) -> fn.apply(a, b), acc, reverse(as)); + public Lazy apply(BiFunction, ? extends Lazy> fn, Lazy acc, Iterable as) { + return lazyRec((f, lazyIt) -> lazyIt.flatMap(it -> it.hasNext() + ? fn.apply(it.next(), f.apply(lazy(it))) + : acc), + lazy(as::iterator)); } @SuppressWarnings("unchecked") public static FoldRight foldRight() { - return INSTANCE; + return (FoldRight) INSTANCE; } - public static Fn2, B> foldRight(BiFunction fn) { + public static Fn2, Iterable, Lazy> foldRight( + BiFunction, ? extends Lazy> fn) { return FoldRight.foldRight().apply(fn); } - public static Fn1, B> foldRight(BiFunction fn, B acc) { + public static Fn1, Lazy> foldRight( + BiFunction, ? extends Lazy> fn, + Lazy acc) { return FoldRight.foldRight(fn).apply(acc); } - public static B foldRight(BiFunction fn, B acc, Iterable as) { + public static Lazy foldRight(BiFunction, ? extends Lazy> fn, Lazy acc, + Iterable as) { return FoldRight.foldRight(fn, acc).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java index c8eb56d7c..180d55c80 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java @@ -1,5 +1,7 @@ package com.jnape.palatable.lambda.functor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; + import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -47,6 +49,22 @@ public interface Applicative extends Functor */ Applicative zip(Applicative, App> appFn); + /** + * Given a {@link Lazy lazy} instance of this applicative over a mapping function, "zip" the two instances together + * using whatever application semantics the current applicative supports. This is useful for applicatives that + * support lazy evaluation and early termination. + * + * @param lazyAppFn the lazy other applicative instance + * @param the resulting applicative parameter type + * @return the mapped applicative + * @see com.jnape.palatable.lambda.adt.Maybe + * @see com.jnape.palatable.lambda.adt.Either + */ + default Lazy> lazyZip( + Lazy, App>> lazyAppFn) { + return lazyAppFn.fmap(this::zip); + } + @Override default Applicative fmap(Function fn) { return zip(pure(fn)); diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index 40a732247..965567501 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -25,26 +25,50 @@ public , FGA extends Applicative> FGA getCom return fga.fmap(Applicative::coerce).coerce(); } + /** + * {@inheritDoc} + */ @Override public Compose fmap(Function fn) { return new Compose<>(fga.fmap(g -> g.fmap(fn))); } + /** + * {@inheritDoc} + */ @Override public Compose pure(B b) { return new Compose<>(fga.fmap(g -> g.pure(b))); } + /** + * {@inheritDoc} + */ @Override public Compose zip(Applicative, Compose> appFn) { return new Compose<>(fga.zip(appFn.>>coerce().getCompose().fmap(gFn -> g -> g.zip(gFn)))); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Compose>> lazyAppFn) { + return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + + /** + * {@inheritDoc} + */ @Override public Compose discardL(Applicative> appB) { return Applicative.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Compose discardR(Applicative> appB) { return Applicative.super.discardR(appB).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index 6de15b769..6ef443106 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -53,27 +53,50 @@ public Const pure(C c) { return (Const) this; } + /** + * {@inheritDoc} + */ @Override public Const zip(Applicative, Const> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip(Lazy, Const>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + + /** + * {@inheritDoc} + */ @Override public Const discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Const discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Const flatMap(Function>> f) { return (Const) this; } + /** + * {@inheritDoc} + */ @Override public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( Function fn, Function pure) { @@ -81,11 +104,7 @@ public Const flatMap(Function the new left parameter type (the value) - * @return a Const over Z (the new value) and B (the same phantom parameter) + * {@inheritDoc} */ @Override @SuppressWarnings("unchecked") @@ -94,11 +113,7 @@ public Const biMapL(Function fn) { } /** - * Covariantly map over the right parameter (phantom) type. - * - * @param fn the mapping function - * @param the new right parameter (phantom) type - * @return a Const over A (the same value) and C (the new phantom parameter) + * {@inheritDoc} */ @Override @SuppressWarnings("unchecked") @@ -107,13 +122,7 @@ public Const biMapR(Function fn) { } /** - * Bifunctor's biMap, specialized for Const. - * - * @param lFn the left parameter mapping function - * @param rFn the right parameter mapping function - * @param the new left parameter type - * @param the new right parameter type - * @return a Const over C (the new value) and D (the new phantom parameter) + * {@inheritDoc} */ @Override public Const biMap(Function lFn, diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java index 68e223c40..d9781e8cc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java @@ -45,26 +45,50 @@ public Identity fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override public Identity pure(B b) { return new Identity<>(b); } + /** + * {@inheritDoc} + */ @Override public Identity zip(Applicative, Identity> appFn) { return new Identity<>(appFn.>>coerce().runIdentity().apply(a)); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Identity>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + + /** + * {@inheritDoc} + */ @Override public Identity discardL(Applicative appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Identity discardR(Applicative appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index d659e35a8..7c21845a2 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import java.util.LinkedList; @@ -119,6 +120,14 @@ public final IO zip(Applicative, IO> return new Compose<>(source, a(zip)); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip(Lazy, IO>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java index 4c3e2e18d..e56d0ca39 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.functions.builtin.fn1.Id; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import java.util.function.Function; @@ -59,6 +60,14 @@ default Monad zip(Applicative, M> app return appFn., M>>coerce().flatMap(this::fmap); } + /** + * {@inheritDoc} + */ + @Override + default Lazy> lazyZip(Lazy, M>> lazyAppFn) { + return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java index 6cdf12b1e..88d13a1d6 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft; import com.jnape.palatable.lambda.functions.builtin.fn2.ReduceRight; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.semigroup.Semigroup; import java.util.function.Function; @@ -13,6 +14,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Reverse.reverse; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * A {@link Monoid} is the pairing of a {@link Semigroup} with an identity element. @@ -80,8 +82,8 @@ default A foldLeft(A a, Iterable as) { * {@inheritDoc} */ @Override - default A foldRight(A a, Iterable as) { - return flip().foldMap(id(), reverse(cons(a, as))); + default Lazy foldRight(A a, Iterable as) { + return lazy(() -> flip().foldMap(id(), reverse(cons(a, as)))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java b/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java index b82aea644..10d15de15 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java @@ -3,6 +3,9 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight; +import com.jnape.palatable.lambda.functor.builtin.Lazy; + +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * A Semigroup is a closed, associative category. As closure can be implied by the type signature, and @@ -35,8 +38,8 @@ default A foldLeft(A a, Iterable as) { * @return the folded result * @see FoldRight */ - default A foldRight(A a, Iterable as) { - return FoldRight.foldRight(toBiFunction(), a, as); + default Lazy foldRight(A a, Iterable as) { + return FoldRight.foldRight((y, lazyX) -> lazyX.fmap(x -> apply(x, y)), lazy(a), as); } /** 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 8a40c9cb5..0dfb2b7e3 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -1,6 +1,9 @@ package com.jnape.palatable.lambda.traversable; +import com.jnape.palatable.lambda.functions.builtin.fn1.Empty; +import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import java.util.Iterator; @@ -10,7 +13,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; -import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight.foldRight; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Collections.emptyList; import static java.util.Collections.singleton; @@ -37,11 +40,17 @@ public Iterable unwrap() { return as; } + /** + * {@inheritDoc} + */ @Override public LambdaIterable fmap(Function fn) { return wrap(map(fn, as)); } + /** + * {@inheritDoc} + */ @Override public LambdaIterable pure(B b) { return wrap(singleton(b)); @@ -62,29 +71,57 @@ public LambdaIterable zip(Applicative, L return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, LambdaIterable>> lazyAppFn) { + return Empty.empty(as) + ? lazy(LambdaIterable.empty()) + : Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + + /** + * {@inheritDoc} + */ @Override public LambdaIterable discardL(Applicative appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public LambdaIterable discardR(Applicative appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public LambdaIterable flatMap(Function> f) { return wrap(flatten(map(a -> f.apply(a).>coerce().unwrap(), as))); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") - public , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, - Function pure) { - return foldRight((a, appTrav) -> (AppTrav) appTrav.zip(fn.apply(a).fmap(b -> bs -> (TravB) wrap(cons(b, ((LambdaIterable) bs).unwrap())))), - (AppTrav) pure.apply((TravB) LambdaIterable.empty()), - as); + public , AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { + return FoldRight.foldRight( + (a, lglb) -> fn.apply(a) + .lazyZip(lglb., App>>fmap(appTrav -> appTrav + .fmap(travB -> b -> (TravB) wrap(cons(b, ((LambdaIterable) travB).unwrap()))))) + .fmap(appTrav -> (AppTrav) appTrav), + lazy(pure.apply((TravB) empty())), + as + ).value(); } @Override diff --git a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java index e43e2438f..833447905 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java @@ -23,6 +23,7 @@ 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.Unit.UNIT; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; @@ -223,4 +224,12 @@ public void dyadicPeekDuallyLiftsIO() { assertEquals("foo", stringRef.get()); assertEquals(1, intRef.get()); } + + @Test + public void lazyZip() { + assertEquals(right(2), right(1).lazyZip(lazy(right(x -> x + 1))).value()); + assertEquals(left("foo"), left("foo").lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java index 1e747dc34..fc21833dc 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java @@ -22,6 +22,7 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; @@ -130,4 +131,12 @@ public void invertsIntoChoice2() { assertEquals(Choice2.b(UNIT), nothing().invert()); assertEquals(Choice2.a(1), just(1).invert()); } + + @Test + public void lazyZip() { + assertEquals(just(2), just(1).lazyZip(lazy(() -> just(x -> x + 1))).value()); + assertEquals(nothing(), nothing().lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java index ba44c9caf..c4484c1a3 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java @@ -3,6 +3,7 @@ import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.ApplicativeLaws; import testsupport.traits.BifunctorLaws; @@ -13,7 +14,9 @@ import static com.jnape.palatable.lambda.adt.These.a; import static com.jnape.palatable.lambda.adt.These.b; import static com.jnape.palatable.lambda.adt.These.both; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static org.junit.Assert.assertEquals; @RunWith(Traits.class) public class TheseTest { @@ -22,4 +25,15 @@ public class TheseTest { public Subjects> testSubject() { return subjects(a("foo"), b(1), both("foo", 1)); } + + @Test + public void lazyZip() { + assertEquals(b(2), b(1).lazyZip(lazy(b(x -> x + 1))).value()); + assertEquals(b(2), b(1).lazyZip(lazy(both("foo", x -> x + 1))).value()); + assertEquals(both("bar", 2), both("foo", 1).lazyZip(lazy(both("bar", x -> x + 1))).value()); + assertEquals(both("foo", 2), both("foo", 1).lazyZip(lazy(b(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index f0c7cb043..57b1696f8 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -27,6 +27,7 @@ import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.equalTo; @@ -209,4 +210,13 @@ public void cascadingWithResourcesClosesInInverseOrder() { c -> success(1))); assertEquals(asList("close c", "close b", "close a"), closeMessages); } + + @Test + public void lazyZip() { + assertEquals(success(2), success(1).lazyZip(lazy(success(x -> x + 1))).value()); + IllegalStateException e = new IllegalStateException(); + assertEquals(failure(e), failure(e).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java index 49b489192..ea4c27160 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java @@ -14,6 +14,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -39,4 +40,12 @@ public void divergeStaysInChoice() { assertEquals(Choice3.a(1), a.diverge()); assertEquals(Choice3.b(true), b.diverge()); } + + @Test + public void lazyZip() { + assertEquals(b(2), b(1).lazyZip(lazy(b(x -> x + 1))).value()); + assertEquals(a("foo"), a("foo").lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java index 1d04ec9a5..2deefbb91 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java @@ -15,6 +15,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice3.a; import static com.jnape.palatable.lambda.adt.choice.Choice3.b; import static com.jnape.palatable.lambda.adt.choice.Choice3.c; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -50,4 +51,15 @@ public void divergeStaysInChoice() { assertEquals(Choice4.b("two"), b.diverge()); assertEquals(Choice4.c(true), c.diverge()); } + + @Test + public void lazyZip() { + assertEquals(Choice3.c(2), c(1).lazyZip(lazy(c(x -> x + 1))).value()); + assertEquals(Choice3.b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(Choice3.a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java index 0b70141e7..1e20850d6 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java @@ -16,6 +16,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice4.b; import static com.jnape.palatable.lambda.adt.choice.Choice4.c; import static com.jnape.palatable.lambda.adt.choice.Choice4.d; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -55,4 +56,18 @@ public void divergeStaysInChoice() { assertEquals(Choice5.c(true), c.diverge()); assertEquals(Choice5.d(4D), d.diverge()); } + + @Test + public void lazyZip() { + assertEquals(d(2), d(1).lazyZip(lazy(d(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java index d0ea885e5..bfccafcb9 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java @@ -17,6 +17,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice5.c; import static com.jnape.palatable.lambda.adt.choice.Choice5.d; import static com.jnape.palatable.lambda.adt.choice.Choice5.e; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -60,4 +61,21 @@ public void divergeStaysInChoice() { assertEquals(Choice6.d(4D), d.diverge()); assertEquals(Choice6.e('z'), e.diverge()); } + + @Test + public void lazyZip() { + assertEquals(e(2), e(1).lazyZip(lazy(e(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(d(1), d(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java index 2262884b5..0606c892d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java @@ -21,6 +21,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice6.d; import static com.jnape.palatable.lambda.adt.choice.Choice6.e; import static com.jnape.palatable.lambda.adt.choice.Choice6.f; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -70,4 +71,24 @@ public void divergeStaysInChoice() { assertEquals(Choice7.e('z'), e.diverge()); assertEquals(Choice7.f(5L), f.diverge()); } + + @Test + public void lazyZip() { + assertEquals(f(2), f(1).lazyZip(lazy(f(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(d(1), d(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(e(1), e(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java index 27bf111d0..5bec8a5b4 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java @@ -22,6 +22,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice7.e; import static com.jnape.palatable.lambda.adt.choice.Choice7.f; import static com.jnape.palatable.lambda.adt.choice.Choice7.g; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -75,4 +76,27 @@ public void divergeStaysInChoice() { assertEquals(Choice8.f(5L), f.diverge()); assertEquals(Choice8.g(6F), g.diverge()); } + + @Test + public void lazyZip() { + assertEquals(g(2), g(1).lazyZip(lazy(g(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(d(1), d(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(e(1), e(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(f(1), f(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java index 24fede69b..d71e3228d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java @@ -23,6 +23,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice8.f; import static com.jnape.palatable.lambda.adt.choice.Choice8.g; import static com.jnape.palatable.lambda.adt.choice.Choice8.h; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -68,4 +69,30 @@ public void convergeStaysInChoice() { assertEquals(Choice7.g(6F), g.converge(convergenceFn)); assertEquals(Choice7.b("7"), h.converge(convergenceFn)); } + + @Test + public void lazyZip() { + assertEquals(h(2), h(1).lazyZip(lazy(h(x -> x + 1))).value()); + assertEquals(a(1), a(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(b(1), b(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(c(1), c(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(d(1), d(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(e(1), e(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(f(1), f(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + assertEquals(g(1), g(1).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java index b40915da7..912ee9b4a 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java @@ -1,17 +1,22 @@ package com.jnape.palatable.lambda.functions.builtin.fn3; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.EmptyIterableSupport; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Iterate.iterate; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight.foldRight; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; import static testsupport.functions.ExplainFold.explainFold; @RunWith(Traits.class) @@ -19,14 +24,25 @@ public class FoldRightTest { @TestTraits({EmptyIterableSupport.class}) public Fn1, Iterable> createTestSubject() { - return foldRight((o, objects) -> objects, singletonList(new Object())); + return foldRight((o, objects) -> objects, lazy(singletonList(new Object()))).fmap(Lazy::value); } @Test public void foldRightAccumulatesRightToLeft() { - assertThat( - foldRight(explainFold(), "5", asList("1", "2", "3", "4")), - is("(1 + (2 + (3 + (4 + 5))))") + assertThat(foldRight((a, lazyB) -> lazyB.fmap(b -> explainFold().apply(a, b)), + lazy("5"), + asList("1", "2", "3", "4")) + .value(), + is("(1 + (2 + (3 + (4 + 5))))") ); } + + @Test + public void stackSafe() { + Lazy lazy = foldRight((x, lazyY) -> x < STACK_EXPLODING_NUMBER ? lazyY.fmap(y -> y) : lazy(x), + lazy(0), + iterate(x -> x + 1, 0)); + + assertEquals(STACK_EXPLODING_NUMBER, lazy.value()); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java index 68f99d943..301108b0f 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java @@ -9,6 +9,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.Iterate.iterate; import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight.foldRight; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -51,9 +52,10 @@ public void doesNotHaveNextIfNoElementsLeft() { @Test public void stackSafety() { Integer stackBlowingNumber = 10_000; - Iterable ints = foldRight((x, acc) -> () -> new ConsingIterator<>(x, acc), - (Iterable) Collections.emptyList(), - take(stackBlowingNumber, iterate(x -> x + 1, 1))); + Iterable ints = foldRight((x, lazyAcc) -> lazyAcc.fmap(acc -> () -> new ConsingIterator<>(x, acc)), + lazy((Iterable) Collections.emptyList()), + take(stackBlowingNumber, iterate(x -> x + 1, 1))) + .value(); assertEquals(stackBlowingNumber, take(1, drop(stackBlowingNumber - 1, ints)).iterator().next()); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java index ec20057bc..3291b6b1b 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java @@ -16,6 +16,6 @@ public void foldLeft() { @Test public void foldRight() { Semigroup sum = (x, y) -> x + y; - assertEquals((Integer) 6, sum.foldRight(0, asList(1, 2, 3))); + assertEquals((Integer) 6, sum.foldRight(0, asList(1, 2, 3)).value()); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java index 9947e7f3a..e76f48e5e 100644 --- a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.traversable; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -12,11 +13,22 @@ import java.util.function.Function; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.traversable.LambdaIterable.empty; +import static com.jnape.palatable.lambda.traversable.LambdaIterable.wrap; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.util.Arrays.asList; import static java.util.Collections.singleton; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; import static testsupport.matchers.IterableMatcher.iterates; @RunWith(Traits.class) @@ -24,13 +36,36 @@ public class LambdaIterableTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, TraversableLaws.class, MonadLaws.class}) public Subjects> testSubject() { - return subjects(LambdaIterable.empty(), LambdaIterable.wrap(singleton(1)), LambdaIterable.wrap(replicate(100, 1))); + return subjects(LambdaIterable.empty(), wrap(singleton(1)), wrap(replicate(100, 1))); } @Test public void zipAppliesCartesianProductOfFunctionsAndValues() { - LambdaIterable> fns = LambdaIterable.wrap(asList(x -> x + 1, x -> x - 1)); - LambdaIterable xs = LambdaIterable.wrap(asList(1, 2, 3)); + LambdaIterable> fns = wrap(asList(x -> x + 1, x -> x - 1)); + LambdaIterable xs = wrap(asList(1, 2, 3)); assertThat(xs.zip(fns).unwrap(), iterates(2, 3, 4, 0, 1, 2)); } + + @Test + public void earlyTraverseTermination() { + assertEquals(nothing(), wrap(repeat(1)).traverse(x -> nothing(), Maybe::just)); + assertEquals(nothing(), LambdaIterable.>wrap(cons(just(1), repeat(nothing()))) + .traverse(id(), Maybe::just)); + } + + @Test + public void traverseStackSafety() { + Maybe> traversed = wrap(replicate(STACK_EXPLODING_NUMBER, just(1))) + .traverse(id(), Maybe::just); + assertEquals(just(STACK_EXPLODING_NUMBER.longValue()), + traversed.fmap(LambdaIterable::unwrap).fmap(size())); + } + + @Test + public void lazyZip() { + assertEquals(wrap(singleton(2)), wrap(singleton(1)).lazyZip(lazy(wrap(singleton(x -> x + 1)))).value()); + assertEquals(empty(), empty().lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file diff --git a/src/test/java/testsupport/traits/ApplicativeLaws.java b/src/test/java/testsupport/traits/ApplicativeLaws.java index 6255798ce..42fd8bbde 100644 --- a/src/test/java/testsupport/traits/ApplicativeLaws.java +++ b/src/test/java/testsupport/traits/ApplicativeLaws.java @@ -11,6 +11,8 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Arrays.asList; import static java.util.function.Function.identity; @@ -26,7 +28,8 @@ public void test(Applicative applicative) { this::testHomomorphism, this::testInterchange, this::testDiscardL, - this::testDiscardR) + this::testDiscardR, + this::testLazyZip) ) .peek(s -> { throw new AssertionError("The following Applicative laws did not hold for instance of " + applicative.getClass() + ": \n\t - " + s); @@ -37,8 +40,8 @@ private Maybe testIdentity(Applicative applicative) { Applicative v = applicative.pure(1); Applicative, App> pureId = v.pure(identity()); return v.zip(pureId).equals(v) - ? nothing() - : just("identity (v.zip(pureId).equals(v))"); + ? nothing() + : just("identity (v.zip(pureId).equals(v))"); } private Maybe testComposition(Applicative applicative) { @@ -53,8 +56,8 @@ private Maybe testComposition(Applicative applicative) { Applicative, ? extends Function, ? extends Function>>, App> pureCompose = u.pure(compose); return w.zip(v.zip(u.zip(pureCompose))).equals(w.zip(v).zip(u)) - ? nothing() - : just("composition (w.zip(v.zip(u.zip(pureCompose))).equals((w.zip(v)).zip(u)))"); + ? nothing() + : just("composition (w.zip(v.zip(u.zip(pureCompose))).equals((w.zip(v)).zip(u)))"); } private Maybe testHomomorphism(Applicative applicative) { @@ -65,8 +68,8 @@ private Maybe testHomomorphism(Applicative applicative) { Applicative, App> pureF = applicative.pure(f); Applicative pureFx = applicative.pure(f.apply(x)); return pureX.zip(pureF).equals(pureFx) - ? nothing() - : just("homomorphism (pureX.zip(pureF).equals(pureFx))"); + ? nothing() + : just("homomorphism (pureX.zip(pureF).equals(pureFx))"); } private Maybe testInterchange(Applicative applicative) { @@ -75,8 +78,8 @@ private Maybe testInterchange(Applicative applicative) { Applicative pureY = applicative.pure(y); return pureY.zip(u).equals(u.zip(applicative.pure(f -> f.apply(y)))) - ? nothing() - : just("interchange (pureY.zip(u).equals(u.zip(applicative.pure(f -> f.apply(y)))))"); + ? nothing() + : just("interchange (pureY.zip(u).equals(u.zip(applicative.pure(f -> f.apply(y)))))"); } private Maybe testDiscardL(Applicative applicative) { @@ -84,8 +87,8 @@ private Maybe testDiscardL(Applicative applicative) { Applicative v = applicative.pure("v"); return u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(identity()))))) - ? nothing() - : just("discardL u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(identity())))))"); + ? nothing() + : just("discardL u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(identity())))))"); } private Maybe testDiscardR(Applicative applicative) { @@ -93,7 +96,13 @@ private Maybe testDiscardR(Applicative applicative) { Applicative v = applicative.pure("v"); return u.discardR(v).equals(v.zip(u.zip(applicative.pure(constantly())))) - ? nothing() - : just("discardR u.discardR(v).equals(v.zip(u.zip(applicative.pure(constantly()))))"); + ? nothing() + : just("discardR u.discardR(v).equals(v.zip(u.zip(applicative.pure(constantly()))))"); + } + + private Maybe testLazyZip(Applicative applicative) { + return applicative.lazyZip(lazy(applicative.pure(id()))).value().equals(applicative.zip(applicative.pure(id()))) + ? nothing() + : just("lazyZip app.zip(lazy(app.pure(id()))).equals(app.zip(app.pure(id())))"); } } From 329e78458dcb3746f3ef02d4b12bdf10d2cfe86c Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 13 Apr 2019 18:15:04 -0500 Subject: [PATCH 117/348] Eliminating all raw types --- CHANGELOG.md | 2 ++ .../jnape/palatable/lambda/adt/Either.java | 17 +++++++--- .../com/jnape/palatable/lambda/adt/Maybe.java | 29 +++++++++------- .../com/jnape/palatable/lambda/adt/These.java | 6 ++-- .../com/jnape/palatable/lambda/adt/Try.java | 6 ++-- .../palatable/lambda/adt/choice/Choice2.java | 8 +++-- .../palatable/lambda/adt/choice/Choice3.java | 6 ++-- .../palatable/lambda/adt/choice/Choice4.java | 6 ++-- .../palatable/lambda/adt/choice/Choice5.java | 6 ++-- .../palatable/lambda/adt/choice/Choice6.java | 6 ++-- .../palatable/lambda/adt/choice/Choice7.java | 6 ++-- .../palatable/lambda/adt/choice/Choice8.java | 6 ++-- .../palatable/lambda/adt/hlist/HList.java | 4 +-- .../palatable/lambda/adt/hlist/Index.java | 2 +- .../lambda/adt/hlist/SingletonHList.java | 21 +++++++----- .../palatable/lambda/adt/hlist/Tuple2.java | 10 +++--- .../palatable/lambda/adt/hlist/Tuple3.java | 6 ++-- .../palatable/lambda/adt/hlist/Tuple4.java | 6 ++-- .../palatable/lambda/adt/hlist/Tuple5.java | 6 ++-- .../palatable/lambda/adt/hlist/Tuple6.java | 6 ++-- .../palatable/lambda/adt/hlist/Tuple7.java | 7 ++-- .../palatable/lambda/adt/hlist/Tuple8.java | 7 ++-- .../lambda/adt/hmap/TypeSafeKey.java | 19 ++++++----- .../jnape/palatable/lambda/functions/Fn1.java | 6 ++-- .../functions/builtin/fn1/CatMaybes.java | 4 +-- .../functions/builtin/fn1/Coalesce.java | 4 +-- .../functions/builtin/fn1/Constantly.java | 4 +-- .../lambda/functions/builtin/fn1/Cycle.java | 4 +-- .../functions/builtin/fn1/Distinct.java | 4 +-- .../lambda/functions/builtin/fn1/Empty.java | 4 +-- .../lambda/functions/builtin/fn1/Flatten.java | 4 +-- .../lambda/functions/builtin/fn1/Force.java | 4 +-- .../lambda/functions/builtin/fn1/Head.java | 4 +-- .../lambda/functions/builtin/fn1/Id.java | 4 +-- .../lambda/functions/builtin/fn1/Init.java | 4 +-- .../lambda/functions/builtin/fn1/Inits.java | 4 +-- .../lambda/functions/builtin/fn1/Last.java | 4 +-- .../functions/builtin/fn1/Magnetize.java | 4 +-- .../lambda/functions/builtin/fn1/Not.java | 4 +-- .../functions/builtin/fn1/Occurrences.java | 4 +-- .../lambda/functions/builtin/fn1/Repeat.java | 4 +-- .../lambda/functions/builtin/fn1/Reverse.java | 4 +-- .../lambda/functions/builtin/fn1/Sort.java | 4 +-- .../lambda/functions/builtin/fn1/Tail.java | 4 +-- .../lambda/functions/builtin/fn1/Tails.java | 4 +-- .../lambda/functions/builtin/fn1/Uncons.java | 4 +-- .../lambda/functions/builtin/fn2/All.java | 4 +-- .../lambda/functions/builtin/fn2/Alter.java | 4 +-- .../lambda/functions/builtin/fn2/Any.java | 4 +-- .../lambda/functions/builtin/fn2/Both.java | 4 +-- .../builtin/fn2/CartesianProduct.java | 4 +-- .../lambda/functions/builtin/fn2/CmpEq.java | 4 +-- .../lambda/functions/builtin/fn2/Cons.java | 2 +- .../functions/builtin/fn2/Difference.java | 4 +-- .../lambda/functions/builtin/fn2/Drop.java | 4 +-- .../functions/builtin/fn2/DropWhile.java | 4 +-- .../lambda/functions/builtin/fn2/Eq.java | 4 +-- .../lambda/functions/builtin/fn2/Filter.java | 4 +-- .../lambda/functions/builtin/fn2/Find.java | 4 +-- .../lambda/functions/builtin/fn2/GT.java | 4 +-- .../lambda/functions/builtin/fn2/GTE.java | 4 +-- .../lambda/functions/builtin/fn2/GroupBy.java | 4 +-- .../functions/builtin/fn2/InGroupsOf.java | 4 +-- .../functions/builtin/fn2/Intersection.java | 4 +-- .../functions/builtin/fn2/Intersperse.java | 4 +-- .../lambda/functions/builtin/fn2/Into.java | 4 +-- .../lambda/functions/builtin/fn2/Into1.java | 4 +-- .../lambda/functions/builtin/fn2/Into3.java | 4 +-- .../lambda/functions/builtin/fn2/Into4.java | 4 +-- .../lambda/functions/builtin/fn2/Into5.java | 4 +-- .../lambda/functions/builtin/fn2/Into6.java | 4 +-- .../lambda/functions/builtin/fn2/Into7.java | 4 +-- .../lambda/functions/builtin/fn2/Into8.java | 4 +-- .../lambda/functions/builtin/fn2/Iterate.java | 4 +-- .../lambda/functions/builtin/fn2/LT.java | 4 +-- .../lambda/functions/builtin/fn2/LTE.java | 4 +-- .../functions/builtin/fn2/MagnetizeBy.java | 4 +-- .../lambda/functions/builtin/fn2/Map.java | 4 +-- .../functions/builtin/fn2/Partial2.java | 4 +-- .../functions/builtin/fn2/Partial3.java | 4 +-- .../functions/builtin/fn2/Partition.java | 4 +-- .../lambda/functions/builtin/fn2/Peek.java | 4 +-- .../lambda/functions/builtin/fn2/Peek2.java | 4 +-- .../functions/builtin/fn2/PrependAll.java | 4 +-- .../functions/builtin/fn2/ReduceLeft.java | 4 +-- .../functions/builtin/fn2/ReduceRight.java | 4 +-- .../functions/builtin/fn2/Replicate.java | 4 +-- .../functions/builtin/fn2/Sequence.java | 22 ++++++------- .../lambda/functions/builtin/fn2/Slide.java | 4 +-- .../lambda/functions/builtin/fn2/Snoc.java | 4 +-- .../lambda/functions/builtin/fn2/SortBy.java | 4 +-- .../functions/builtin/fn2/SortWith.java | 4 +-- .../lambda/functions/builtin/fn2/Span.java | 4 +-- .../lambda/functions/builtin/fn2/Take.java | 4 +-- .../functions/builtin/fn2/TakeWhile.java | 4 +-- .../lambda/functions/builtin/fn2/ToArray.java | 4 +-- .../functions/builtin/fn2/ToCollection.java | 4 +-- .../lambda/functions/builtin/fn2/ToMap.java | 4 +-- .../lambda/functions/builtin/fn2/Tupler2.java | 4 +-- .../lambda/functions/builtin/fn2/Unfoldr.java | 4 +-- .../lambda/functions/builtin/fn2/Zip.java | 4 +-- .../lambda/functions/builtin/fn3/Between.java | 4 +-- .../lambda/functions/builtin/fn3/Clamp.java | 4 +-- .../lambda/functions/builtin/fn3/CmpEqBy.java | 4 +-- .../functions/builtin/fn3/FoldLeft.java | 4 +-- .../lambda/functions/builtin/fn3/GTBy.java | 4 +-- .../lambda/functions/builtin/fn3/GTEBy.java | 4 +-- .../lambda/functions/builtin/fn3/LTBy.java | 4 +-- .../lambda/functions/builtin/fn3/LTEBy.java | 4 +-- .../lambda/functions/builtin/fn3/LiftA2.java | 33 +++++++++++-------- .../functions/builtin/fn3/ScanLeft.java | 4 +-- .../lambda/functions/builtin/fn3/Times.java | 4 +-- .../lambda/functions/builtin/fn3/ZipWith.java | 4 +-- .../functions/builtin/fn4/IfThenElse.java | 4 +-- .../lambda/functions/builtin/fn4/LiftA3.java | 16 ++++----- .../functions/builtin/fn4/RateLimit.java | 4 +-- .../lambda/functions/builtin/fn5/LiftA4.java | 18 +++++----- .../lambda/functions/builtin/fn6/LiftA5.java | 20 +++++------ .../lambda/functions/builtin/fn7/LiftA6.java | 28 ++++++++-------- .../lambda/functions/builtin/fn8/LiftA7.java | 24 +++++++------- .../functions/recursion/RecursiveResult.java | 9 +++-- .../functions/recursion/Trampoline.java | 4 +-- .../lambda/functions/specialized/Kleisli.java | 4 +-- .../lambda/functions/specialized/Noop.java | 4 +-- .../palatable/lambda/functor/Applicative.java | 4 +-- .../palatable/lambda/functor/Bifunctor.java | 2 +- .../lambda/functor/BoundedBifunctor.java | 7 +++- .../lambda/functor/Contravariant.java | 2 +- .../palatable/lambda/functor/Functor.java | 2 +- .../palatable/lambda/functor/Profunctor.java | 2 +- .../palatable/lambda/functor/Strong.java | 2 +- .../lambda/functor/builtin/Compose.java | 3 +- .../lambda/functor/builtin/Const.java | 11 +++++-- .../lambda/functor/builtin/Identity.java | 19 ++++++----- .../lambda/iteration/ImmutableQueue.java | 4 +-- .../lambda/iteration/ImmutableStack.java | 4 +-- .../com/jnape/palatable/lambda/lens/Iso.java | 24 +++++++++----- .../com/jnape/palatable/lambda/lens/Lens.java | 11 +++++-- .../jnape/palatable/lambda/lens/LensLike.java | 6 ++-- .../palatable/lambda/lens/functions/Over.java | 6 ++-- .../palatable/lambda/lens/functions/Set.java | 4 +-- .../lambda/lens/functions/Under.java | 4 +-- .../palatable/lambda/lens/functions/View.java | 4 +-- .../jnape/palatable/lambda/monad/Monad.java | 6 ++-- .../lambda/monoid/builtin/AddAll.java | 4 +-- .../lambda/monoid/builtin/Collapse.java | 4 +-- .../lambda/monoid/builtin/Compose.java | 4 +-- .../lambda/monoid/builtin/Concat.java | 4 +-- .../lambda/monoid/builtin/First.java | 4 +-- .../palatable/lambda/monoid/builtin/Last.java | 4 +-- .../lambda/monoid/builtin/LeftAll.java | 4 +-- .../lambda/monoid/builtin/LeftAny.java | 4 +-- .../lambda/monoid/builtin/Merge.java | 4 +-- .../lambda/monoid/builtin/MergeMaps.java | 4 +-- .../lambda/monoid/builtin/RightAny.java | 4 +-- .../lambda/monoid/builtin/RunAll.java | 4 +-- .../lambda/monoid/builtin/Union.java | 4 +-- .../lambda/semigroup/builtin/Absent.java | 2 +- .../lambda/semigroup/builtin/Collapse.java | 4 +-- .../lambda/semigroup/builtin/Compose.java | 4 +-- .../lambda/semigroup/builtin/LeftAll.java | 4 +-- .../lambda/semigroup/builtin/LeftAny.java | 4 +-- .../lambda/semigroup/builtin/Max.java | 4 +-- .../lambda/semigroup/builtin/MaxBy.java | 4 +-- .../lambda/semigroup/builtin/Merge.java | 4 +-- .../lambda/semigroup/builtin/Min.java | 4 +-- .../lambda/semigroup/builtin/MinBy.java | 4 +-- .../lambda/semigroup/builtin/RightAll.java | 4 +-- .../lambda/semigroup/builtin/RightAny.java | 4 +-- .../lambda/semigroup/builtin/RunAll.java | 4 +-- .../lambda/traversable/LambdaIterable.java | 15 +++++---- .../lambda/traversable/LambdaMap.java | 15 +++++---- .../lambda/traversable/Traversable.java | 4 +-- .../functions/specialized/KleisliTest.java | 4 +-- .../lambda/functor/BifunctorTest.java | 6 ++-- .../lambda/functor/ProfunctorTest.java | 6 ++-- .../lambda/functor/builtin/ComposeTest.java | 2 +- .../jnape/palatable/lambda/lens/LensTest.java | 4 +-- src/test/java/testsupport/EquatableM.java | 2 +- .../InvocationRecordingBifunctor.java | 2 +- .../InvocationRecordingProfunctor.java | 2 +- .../testsupport/traits/ApplicativeLaws.java | 2 +- .../testsupport/traits/BifunctorLaws.java | 14 ++++---- .../java/testsupport/traits/FunctorLaws.java | 10 +++--- .../java/testsupport/traits/MonadLaws.java | 2 +- .../testsupport/traits/TraversableLaws.java | 25 +++++++------- 186 files changed, 594 insertions(+), 490 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c028d0d3f..ec8477ed1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). factory methods should continue to work (by simply targeting `Supplier` now instead of an anonymous `IO`), but some might need to be reworked, and subtyping is obviously no longer supported. - ***Breaking Change***: `FoldRight` now requires `Lazy` as part of its interface to support short-circuiting operations +- ***Breaking Change***: Eliminated all raw types and java11 warnings. This required using capture in unification + parameters for Functor and friends, so nearly every functor's type-signature changed. - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ### Added 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 c90ee9dd8..cea6eac17 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -32,7 +32,11 @@ * @param The left parameter type * @param The right parameter type */ -public abstract class Either implements CoProduct2>, Monad>, Traversable>, Bifunctor { +public abstract class Either implements + CoProduct2>, + Monad>, + Traversable>, + Bifunctor> { private Either() { } @@ -125,8 +129,9 @@ public final Either filter(Function pred, * @return the Either resulting from applying rightFn to this right value, or this left value if left */ @Override + @SuppressWarnings("RedundantTypeArguments") public Either flatMap(Function>> rightFn) { - return match(Either::left, rightFn.andThen(Applicative::coerce)); + return match(Either::left, rightFn.andThen(Monad>::coerce)); } @Override @@ -146,6 +151,7 @@ public final Either invert() { * @return the merged Either */ @SafeVarargs + @SuppressWarnings("varargs") public final Either merge(BiFunction leftFn, BiFunction rightFn, Either... others) { @@ -279,9 +285,10 @@ public final Either discardR(Applicative> appB) { */ @Override @SuppressWarnings("unchecked") - public final >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, - Function pure) { + public final , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return (AppTrav) match(l -> pure.apply((TravB) left(l)), r -> fn.apply(r).fmap(Either::right)); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index 7d07ba4c5..aeaf59d3c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -32,7 +32,10 @@ * @param the optional parameter type * @see Optional */ -public abstract class Maybe implements CoProduct2>, Monad, Traversable { +public abstract class Maybe implements + CoProduct2>, + Monad>, + Traversable> { private Maybe() { } @@ -131,7 +134,7 @@ public final Maybe fmap(Function fn) { * {@inheritDoc} */ @Override - public final Maybe zip(Applicative, Maybe> appFn) { + public final Maybe zip(Applicative, Maybe> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -143,7 +146,7 @@ public final Maybe zip(Applicative, Mayb * @return the zipped {@link Maybe} */ @Override - public Lazy> lazyZip(Lazy, Maybe>> lazyAppFn) { + public Lazy> lazyZip(Lazy, Maybe>> lazyAppFn) { return match(constantly(lazy(nothing())), a -> lazyAppFn.fmap(maybeF -> maybeF.fmap(f -> f.apply(a)).coerce())); } @@ -152,7 +155,7 @@ public Lazy> lazyZip(Lazy Maybe discardL(Applicative appB) { + public final Maybe discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } @@ -160,16 +163,17 @@ public final Maybe discardL(Applicative appB) { * {@inheritDoc} */ @Override - public final Maybe discardR(Applicative appB) { + public final Maybe discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } /** * {@inheritDoc} */ + @SuppressWarnings("RedundantTypeArguments") @Override - public final Maybe flatMap(Function> f) { - return match(constantly(nothing()), f.andThen(Applicative::coerce)); + public final Maybe flatMap(Function>> f) { + return match(constantly(nothing()), f.andThen(Monad>::coerce)); } /** @@ -208,9 +212,10 @@ public final Maybe peek(Consumer consumer) { @Override @SuppressWarnings("unchecked") - public final , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, - Function pure) { + public final , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(__ -> pure.apply((TravB) Maybe.nothing()), a -> (AppTrav) fn.apply(a).fmap(Maybe::just)); } @@ -272,11 +277,11 @@ public static Maybe just(A a) { */ @SuppressWarnings("unchecked") public static Maybe nothing() { - return Nothing.INSTANCE; + return (Maybe) Nothing.INSTANCE; } private static final class Nothing extends Maybe { - private static final Nothing INSTANCE = new Nothing(); + private static final Nothing INSTANCE = new Nothing<>(); private Nothing() { } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index 494dbb38e..e25d0e741 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -57,8 +57,10 @@ public final These pure(C c) { @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(a -> pure.apply((TravB) a(a)), b -> fn.apply(b).fmap(this::pure).fmap(Applicative::coerce).coerce(), into((a, b) -> fn.apply(b).fmap(c -> both(a, c)).fmap(Applicative::coerce).coerce())); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index 5c67e7ebd..63b915122 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -200,8 +200,10 @@ public Try discardR(Applicative> appB) { */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(t -> pure.apply((TravB) failure(t)), a -> fn.apply(a).fmap(Try::success).fmap(Applicative::coerce).coerce()); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index 5efb2c09a..52eeb2455 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -29,7 +29,7 @@ public abstract class Choice2 implements CoProduct2>, Monad>, - Bifunctor, + Bifunctor>, Traversable> { private Choice2() { @@ -151,8 +151,10 @@ public final Choice2 flatMap(Function>, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(a -> pure.apply((TravB) a(a)), b -> fn.apply(b).fmap(Choice2::b).fmap(Applicative::coerce).coerce()); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index d8f984cf7..7ea524505 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -152,8 +152,10 @@ public Choice3 flatMap(Function>, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(a -> pure.apply((TravB) Choice3.a(a)).coerce(), b -> pure.apply((TravB) Choice3.b(b)).coerce(), c -> fn.apply(c).fmap(Choice3::c).fmap(Applicative::coerce).coerce()); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index 0e9a0aebb..be222cbac 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -154,8 +154,10 @@ public Choice4 flatMap(Function>, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(a -> pure.apply((TravB) Choice4.a(a)).coerce(), b -> pure.apply((TravB) Choice4.b(b)).coerce(), c -> pure.apply((TravB) Choice4.c(c)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index ab7a8c2fb..a4c12d21d 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -160,8 +160,10 @@ public Choice5 flatMap(Function>, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(a -> pure.apply((TravB) Choice5.a(a)).coerce(), b -> pure.apply((TravB) Choice5.b(b)).coerce(), c -> pure.apply((TravB) Choice5.c(c)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index 59df7eee1..86e2648f5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -165,8 +165,10 @@ public Choice6 flatMap( */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(a -> pure.apply((TravB) Choice6.a(a)).coerce(), b -> pure.apply((TravB) Choice6.b(b)).coerce(), c -> pure.apply((TravB) Choice6.c(c)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index a5f170e4b..40c678f87 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -169,8 +169,10 @@ public Choice7 flatMap( */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(a -> pure.apply((TravB) Choice7.a(a)).coerce(), b -> pure.apply((TravB) Choice7.b(b)).coerce(), c -> pure.apply((TravB) Choice7.c(c)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index 3cd03e2a9..e8fb9debe 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -163,8 +163,10 @@ public Choice8 flatMap( */ @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return match(a -> pure.apply((TravB) Choice8.a(a)).coerce(), b -> pure.apply((TravB) Choice8.b(b)).coerce(), c -> pure.apply((TravB) Choice8.c(c)), 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 bfb0b8f79..91f19edbe 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 @@ -34,7 +34,7 @@ public final String toString() { HList next = this; while (next != HNil.INSTANCE) { - HCons hCons = (HCons) next; + HCons hCons = (HCons) next; body.append(" ").append(hCons.head).append(" "); next = hCons.tail; if (next != HNil.INSTANCE) @@ -269,7 +269,7 @@ public Tail tail() { @Override public final boolean equals(Object other) { if (other instanceof HCons) { - HCons that = (HCons) other; + HCons that = (HCons) other; return this.head.equals(that.head) && this.tail.equals(that.tail); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Index.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Index.java index 12f1eeebd..6a59384c6 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Index.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Index.java @@ -55,7 +55,7 @@ private Index() { private static final class Z extends Index> { - private static final Z INSTANCE = new Z(); + private static final Z INSTANCE = new Z<>(); @Override public Target get(HCons hList) { diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index 0c8608e31..8a5be88b9 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -19,7 +19,9 @@ * @see Tuple4 * @see Tuple5 */ -public class SingletonHList<_1> extends HCons<_1, HNil> implements Monad<_1, SingletonHList>, Traversable<_1, SingletonHList> { +public class SingletonHList<_1> extends HCons<_1, HNil> implements + Monad<_1, SingletonHList>, + Traversable<_1, SingletonHList> { SingletonHList(_1 _1) { super(_1, nil()); @@ -42,35 +44,38 @@ public <_1Prime> SingletonHList<_1Prime> pure(_1Prime _1Prime) { @Override public <_1Prime> SingletonHList<_1Prime> zip( - Applicative, SingletonHList> appFn) { + Applicative, SingletonHList> appFn) { return Monad.super.zip(appFn).coerce(); } @Override public <_1Prime> Lazy> lazyZip( - Lazy, SingletonHList>> lazyAppFn) { + Lazy, SingletonHList>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); } @Override - public <_1Prime> SingletonHList<_1Prime> discardL(Applicative<_1Prime, SingletonHList> appB) { + public <_1Prime> SingletonHList<_1Prime> discardL(Applicative<_1Prime, SingletonHList> appB) { return Monad.super.discardL(appB).coerce(); } @Override - public <_1Prime> SingletonHList<_1> discardR(Applicative<_1Prime, SingletonHList> appB) { + public <_1Prime> SingletonHList<_1> discardR(Applicative<_1Prime, SingletonHList> appB) { return Monad.super.discardR(appB).coerce(); } @Override - public <_1Prime> SingletonHList<_1Prime> flatMap(Function> f) { + public <_1Prime> SingletonHList<_1Prime> flatMap( + Function>> f) { return f.apply(head()).coerce(); } @Override @SuppressWarnings("unchecked") - public , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return fn.apply(head()).fmap(SingletonHList::new).fmap(Applicative::coerce).coerce(); } 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 7268d0595..06dc1a20a 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 @@ -29,7 +29,7 @@ public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements Product2<_1, _2>, Map.Entry<_1, _2>, Monad<_2, Tuple2<_1, ?>>, - Bifunctor<_1, _2, Tuple2>, + Bifunctor<_1, _2, Tuple2>, Traversable<_2, Tuple2<_1, ?>> { private final _1 _1; @@ -113,7 +113,7 @@ public <_2Prime> Tuple2<_1, _2Prime> zip( @Override public <_2Prime> Lazy> lazyZip( Lazy, Tuple2<_1, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_2Prime, Tuple2<_1, ?>>::coerce); } @Override @@ -133,8 +133,10 @@ public <_2Prime> Tuple2<_1, _2Prime> flatMap(Function>, AppB extends Applicative<_2Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_2Prime, App extends Applicative, TravB extends Traversable<_2Prime, Tuple2<_1, ?>>, + AppB extends Applicative<_2Prime, App>, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return fn.apply(_2).fmap(_2Prime -> fmap(constantly(_2Prime))).fmap(Applicative::coerce).coerce(); } 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 de7116c03..a4601ce19 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 @@ -136,8 +136,10 @@ public <_3Prime> Tuple3<_1, _2, _3Prime> flatMap( @Override @SuppressWarnings("unchecked") - public <_3Prime, App extends Applicative, TravB extends Traversable<_3Prime, Tuple3<_1, _2, ?>>, AppB extends Applicative<_3Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_3Prime, App extends Applicative, TravB extends Traversable<_3Prime, Tuple3<_1, _2, ?>>, + AppB extends Applicative<_3Prime, App>, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return fn.apply(_3).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } 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 b240ab948..6b3c410a5 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 @@ -151,8 +151,10 @@ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> flatMap( @Override @SuppressWarnings("unchecked") - public <_4Prime, App extends Applicative, TravB extends Traversable<_4Prime, Tuple4<_1, _2, _3, ?>>, AppB extends Applicative<_4Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_4Prime, App extends Applicative, TravB extends Traversable<_4Prime, Tuple4<_1, _2, _3, ?>>, + AppB extends Applicative<_4Prime, App>, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return fn.apply(_4).fmap(_4Prime -> fmap(constantly(_4Prime))).fmap(Applicative::coerce).coerce(); } 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 5c9764aff..fe2961fd5 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 @@ -171,8 +171,10 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> flatMap( @Override @SuppressWarnings("unchecked") - public <_5Prime, App extends Applicative, TravB extends Traversable<_5Prime, Tuple5<_1, _2, _3, _4, ?>>, AppB extends Applicative<_5Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_5Prime, App extends Applicative, TravB extends Traversable<_5Prime, Tuple5<_1, _2, _3, _4, ?>>, + AppB extends Applicative<_5Prime, App>, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return fn.apply(_5).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 92b983675..2231c6a63 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -192,8 +192,10 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> flatMap( @Override @SuppressWarnings("unchecked") - public <_6Prime, App extends Applicative, TravB extends Traversable<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>, AppB extends Applicative<_6Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_6Prime, App extends Applicative, TravB extends Traversable<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>, + AppB extends Applicative<_6Prime, App>, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return fn.apply(_6).fmap(_6Prime -> fmap(constantly(_6Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index f3f010e2e..36e39bca8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -212,8 +212,11 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> flatMap( @Override @SuppressWarnings("unchecked") - public <_7Prime, App extends Applicative, TravB extends Traversable<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, AppB extends Applicative<_7Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_7Prime, App extends Applicative, + TravB extends Traversable<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, + AppB extends Applicative<_7Prime, App>, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return fn.apply(_7).fmap(_7Prime -> fmap(constantly(_7Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 6d424e3bb..bbc2123cd 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -231,8 +231,11 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> flatMap( @Override @SuppressWarnings("unchecked") - public <_8Prime, App extends Applicative, TravB extends Traversable<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, AppB extends Applicative<_8Prime, App>, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public <_8Prime, App extends Applicative, + TravB extends Traversable<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, + AppB extends Applicative<_8Prime, App>, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return fn.apply(_8).fmap(_8Prime -> fmap(constantly(_8Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java index 8bae70949..e07936a2f 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java @@ -28,9 +28,10 @@ default TypeSafeKey discardR(Applicative> Iso.Simple discarded = Iso.Simple.super.discardR(appB); return new TypeSafeKey() { @Override - public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { - return discarded.apply(pafb); + public

, F extends Functor, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return discarded.apply(pafb); } @Override @@ -64,9 +65,10 @@ default TypeSafeKey andThen(Iso.Simple f) { Iso.Simple composed = Iso.Simple.super.andThen(f); return new TypeSafeKey() { @Override - public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { - return composed.apply(pafb); + public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { + default

, F extends Functor, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { return (PSFT) pafb; } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 3ea573870..9bff01745 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -20,7 +20,7 @@ * @param The result type */ @FunctionalInterface -public interface Fn1 extends Monad>, Strong, Function { +public interface Fn1 extends Monad>, Strong>, Function { /** * Invoke this function with the given argument. @@ -100,7 +100,7 @@ default Fn1 zip(Fn2 appFn) { */ @Override default Lazy> lazyZip(Lazy, Fn1>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -205,6 +205,7 @@ default Fn1 compose(Function before) { * @param the resulting function's second argument type * @return an {@link Fn2}<Y, Z, B> */ + @SuppressWarnings({"overloads"}) default Fn2 compose(BiFunction before) { return compose(fn2(before)); } @@ -217,6 +218,7 @@ default Fn2 compose(BiFunction the resulting function's second argument type * @return an {@link Fn2}<Y, Z, B> */ + @SuppressWarnings({"overloads"}) default Fn2 compose(Fn2 before) { return fn2(before.fmap(this::compose))::apply; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java index 64b9e0a4c..d74111ba3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java @@ -15,7 +15,7 @@ * @param the {@link Maybe} element type, as well as the resulting {@link Iterable} element type */ public final class CatMaybes implements Fn1>, Iterable> { - private static final CatMaybes INSTANCE = new CatMaybes(); + private static final CatMaybes INSTANCE = new CatMaybes<>(); private CatMaybes() { } @@ -28,7 +28,7 @@ public Iterable apply(Iterable> maybes) { @SuppressWarnings("unchecked") public static CatMaybes catMaybes() { - return INSTANCE; + return (CatMaybes) INSTANCE; } public static Iterable catMaybes(Iterable> as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java index e97fe056f..ce9147028 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java @@ -25,7 +25,7 @@ */ public final class Coalesce implements Fn1>, Either, Iterable>> { - private static final Coalesce INSTANCE = new Coalesce(); + private static final Coalesce INSTANCE = new Coalesce<>(); private Coalesce() { } @@ -42,7 +42,7 @@ public Either, Iterable> apply(Iterable> eithers) { @SuppressWarnings("unchecked") public static Coalesce coalesce() { - return INSTANCE; + return (Coalesce) INSTANCE; } public static Either, Iterable> coalesce(Iterable> eithers) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java index 9f89da517..ed4d367b0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java @@ -11,7 +11,7 @@ */ public final class Constantly implements Fn2 { - private static final Constantly INSTANCE = new Constantly(); + private static final Constantly INSTANCE = new Constantly<>(); private Constantly() { } @@ -23,7 +23,7 @@ public A apply(A a, B b) { @SuppressWarnings("unchecked") public static Constantly constantly() { - return INSTANCE; + return (Constantly) INSTANCE; } public static Fn1 constantly(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java index 652b5470d..10fd2039b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java @@ -13,7 +13,7 @@ */ public final class Cycle implements Fn1, Iterable> { - private static final Cycle INSTANCE = new Cycle(); + private static final Cycle INSTANCE = new Cycle<>(); private Cycle() { } @@ -25,7 +25,7 @@ public Iterable apply(Iterable as) { @SuppressWarnings("unchecked") public static Cycle cycle() { - return INSTANCE; + return (Cycle) INSTANCE; } public static Iterable cycle(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java index 8b39ac2a4..949c2c91e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java @@ -9,7 +9,7 @@ * @param the Iterable element type */ public final class Distinct implements Fn1, Iterable> { - private static final Distinct INSTANCE = new Distinct(); + private static final Distinct INSTANCE = new Distinct<>(); private Distinct() { } @@ -21,7 +21,7 @@ public Iterable apply(Iterable as) { @SuppressWarnings("unchecked") public static Distinct distinct() { - return INSTANCE; + return (Distinct) INSTANCE; } public static Iterable distinct(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java index 9906aa803..b8b0f656b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java @@ -9,7 +9,7 @@ */ public final class Empty implements Predicate> { - private static final Empty INSTANCE = new Empty(); + private static final Empty INSTANCE = new Empty<>(); private Empty() { } @@ -21,7 +21,7 @@ public Boolean apply(Iterable as) { @SuppressWarnings("unchecked") public static Empty empty() { - return INSTANCE; + return (Empty) INSTANCE; } public static Boolean empty(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java index 4c88bdec8..ba05c771d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java @@ -10,7 +10,7 @@ * @param the nested Iterable element type */ public final class Flatten implements Fn1>, Iterable> { - private static final Flatten INSTANCE = new Flatten(); + private static final Flatten INSTANCE = new Flatten<>(); private Flatten() { } @@ -22,7 +22,7 @@ public Iterable apply(Iterable> iterables) { @SuppressWarnings("unchecked") public static Flatten flatten() { - return INSTANCE; + return (Flatten) INSTANCE; } public static Iterable flatten(Iterable> as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java index 511b90b4e..84852199a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java @@ -10,7 +10,7 @@ */ public final class Force implements Fn1, Iterable> { - private static final Force INSTANCE = new Force(); + private static final Force INSTANCE = new Force<>(); private Force() { } @@ -25,7 +25,7 @@ public Iterable apply(Iterable as) { @SuppressWarnings("unchecked") public static Force force() { - return INSTANCE; + return (Force) INSTANCE; } public static Iterable force(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java index e8abf632b..e6b2457e4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java @@ -16,7 +16,7 @@ */ public final class Head implements Fn1, Maybe> { - private static final Head INSTANCE = new Head(); + private static final Head INSTANCE = new Head<>(); private Head() { } @@ -29,7 +29,7 @@ public Maybe apply(Iterable as) { @SuppressWarnings("unchecked") public static Head head() { - return INSTANCE; + return (Head) INSTANCE; } public static Maybe head(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java index 640927f50..62a5871ea 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java @@ -9,7 +9,7 @@ */ public final class Id implements Fn1 { - private static final Id INSTANCE = new Id(); + private static final Id INSTANCE = new Id<>(); private Id() { } @@ -21,6 +21,6 @@ public A apply(A a) { @SuppressWarnings("unchecked") public static Id id() { - return INSTANCE; + return (Id) INSTANCE; } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java index ced05d274..2162e65ee 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java @@ -11,7 +11,7 @@ */ public final class Init implements Fn1, Iterable> { - private static final Init INSTANCE = new Init(); + private static final Init INSTANCE = new Init<>(); private Init() { } @@ -23,7 +23,7 @@ public Iterable apply(Iterable as) { @SuppressWarnings("unchecked") public static Init init() { - return INSTANCE; + return (Init) INSTANCE; } public static Iterable init(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java index 52c0413b6..cb6d7165c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java @@ -19,7 +19,7 @@ */ public final class Inits implements Fn1, Iterable>> { - private static final Inits INSTANCE = new Inits(); + private static final Inits INSTANCE = new Inits<>(); private Inits() { } @@ -31,7 +31,7 @@ public Iterable> apply(Iterable as) { @SuppressWarnings("unchecked") public static Inits inits() { - return INSTANCE; + return (Inits) INSTANCE; } public static Iterable> inits(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java index 4710f7900..9f49e95da 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java @@ -13,7 +13,7 @@ */ public final class Last implements Fn1, Maybe> { - private static final Last INSTANCE = new Last(); + private static final Last INSTANCE = new Last<>(); private Last() { } @@ -29,7 +29,7 @@ public Maybe apply(Iterable as) { @SuppressWarnings("unchecked") public static Last last() { - return INSTANCE; + return (Last) INSTANCE; } public static Maybe last(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java index 47c4d3ed8..b25e3e32a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java @@ -12,7 +12,7 @@ */ public final class Magnetize implements Fn1, Iterable>> { - private static final Magnetize INSTANCE = new Magnetize(); + private static final Magnetize INSTANCE = new Magnetize<>(); private Magnetize() { } @@ -24,7 +24,7 @@ public Iterable> apply(Iterable as) { @SuppressWarnings("unchecked") public static Magnetize magnetize() { - return INSTANCE; + return (Magnetize) INSTANCE; } public static Iterable> magnetize(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java index 5f0bb8691..a7b4956c6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java @@ -11,7 +11,7 @@ * @param the input argument type */ public final class Not implements BiPredicate, A> { - private static final Not INSTANCE = new Not(); + private static final Not INSTANCE = new Not<>(); private Not() { } @@ -23,7 +23,7 @@ public Boolean apply(Function pred, A a) { @SuppressWarnings("unchecked") public static Not not() { - return INSTANCE; + return (Not) INSTANCE; } public static Predicate not(Function pred) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java index 8a9062942..af9e21f39 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java @@ -14,7 +14,7 @@ * @param the {@link Iterable} element type */ public final class Occurrences implements Fn1, Map> { - private static final Occurrences INSTANCE = new Occurrences(); + private static final Occurrences INSTANCE = new Occurrences<>(); private Occurrences() { } @@ -29,7 +29,7 @@ public Map apply(Iterable as) { @SuppressWarnings("unchecked") public static Occurrences occurrences() { - return INSTANCE; + return (Occurrences) INSTANCE; } public static Map occurrences(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java index 4286dbace..68209c874 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java @@ -10,7 +10,7 @@ */ public final class Repeat implements Fn1> { - private static final Repeat INSTANCE = new Repeat(); + private static final Repeat INSTANCE = new Repeat<>(); private Repeat() { } @@ -22,7 +22,7 @@ public Iterable apply(A a) { @SuppressWarnings("unchecked") public static Repeat repeat() { - return INSTANCE; + return (Repeat) INSTANCE; } public static Iterable repeat(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java index 7b50cecbc..3913da8f0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java @@ -11,7 +11,7 @@ */ public final class Reverse implements Fn1, Iterable> { - private static final Reverse INSTANCE = new Reverse(); + private static final Reverse INSTANCE = new Reverse<>(); private Reverse() { } @@ -23,7 +23,7 @@ public Iterable apply(Iterable as) { @SuppressWarnings("unchecked") public static Reverse reverse() { - return INSTANCE; + return (Reverse) INSTANCE; } public static Iterable reverse(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java index 96fb7056d..315b6780c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java @@ -19,7 +19,7 @@ */ public final class Sort> implements Fn1, List> { - private static final Sort INSTANCE = new Sort(); + private static final Sort INSTANCE = new Sort<>(); private Sort() { } @@ -31,7 +31,7 @@ public List apply(Iterable as) { @SuppressWarnings("unchecked") public static > Sort sort() { - return INSTANCE; + return (Sort) INSTANCE; } public static > List sort(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java index 8b954fe07..930b4be95 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java @@ -12,7 +12,7 @@ */ public final class Tail implements Fn1, Iterable> { - private static final Tail INSTANCE = new Tail(); + private static final Tail INSTANCE = new Tail<>(); private Tail() { } @@ -24,7 +24,7 @@ public Iterable apply(Iterable as) { @SuppressWarnings("unchecked") public static Tail tail() { - return INSTANCE; + return (Tail) INSTANCE; } public static Iterable tail(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java index cbdc65589..cffe390d3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java @@ -22,7 +22,7 @@ */ public final class Tails implements Fn1, Iterable>> { - private static final Tails INSTANCE = new Tails(); + private static final Tails INSTANCE = new Tails<>(); private Tails() { } @@ -34,7 +34,7 @@ public Iterable> apply(Iterable as) { @SuppressWarnings("unchecked") public static Tails tails() { - return INSTANCE; + return (Tails) INSTANCE; } public static Iterable> tails(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java index 7c6c807bf..27014940b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java @@ -16,7 +16,7 @@ */ public final class Uncons implements Fn1, Maybe>>> { - private static final Uncons INSTANCE = new Uncons(); + private static final Uncons INSTANCE = new Uncons<>(); private Uncons() { } @@ -28,7 +28,7 @@ public Maybe>> apply(Iterable as) { @SuppressWarnings("unchecked") public static Uncons uncons() { - return INSTANCE; + return (Uncons) INSTANCE; } public static Maybe>> uncons(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java index 2aeb00eca..0019932b4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java @@ -15,7 +15,7 @@ */ public final class All implements BiPredicate, Iterable> { - private static final All INSTANCE = new All(); + private static final All INSTANCE = new All<>(); private All() { } @@ -31,7 +31,7 @@ public Boolean apply(Function predicate, Iterable< @SuppressWarnings("unchecked") public static All all() { - return INSTANCE; + return (All) INSTANCE; } public static Fn1, ? extends Boolean> all(Function predicate) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java index 488de31ce..b12160c1f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -15,7 +15,7 @@ */ public final class Alter implements Fn2, A, IO> { - private static final Alter INSTANCE = new Alter(); + private static final Alter INSTANCE = new Alter<>(); private Alter() { } @@ -27,7 +27,7 @@ public IO apply(Effect effect, A a) { @SuppressWarnings("unchecked") public static Alter alter() { - return INSTANCE; + return (Alter) INSTANCE; } public static Fn1> alter(Effect effect) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java index 6285084f5..eacb359b3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java @@ -15,7 +15,7 @@ */ public final class Any implements BiPredicate, Iterable> { - private static final Any INSTANCE = new Any(); + private static final Any INSTANCE = new Any<>(); private Any() { } @@ -31,7 +31,7 @@ public Boolean apply(Function predicate, Iterable< @SuppressWarnings("unchecked") public static Any any() { - return INSTANCE; + return (Any) INSTANCE; } public static Predicate> any(Function predicate) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java index 04bce60f5..0693437cd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java @@ -16,7 +16,7 @@ */ public final class Both implements Fn3, Function, A, Tuple2> { - private static final Both INSTANCE = new Both(); + private static final Both INSTANCE = new Both<>(); private Both() { } @@ -30,7 +30,7 @@ public Tuple2 apply(Function f, @SuppressWarnings("unchecked") public static Both both() { - return INSTANCE; + return (Both) INSTANCE; } public static Fn1, Fn1>> both( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java index aa883f86c..e6663cfe3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java @@ -21,7 +21,7 @@ */ public final class CartesianProduct implements Fn2, Iterable, Iterable>> { - private static final CartesianProduct INSTANCE = new CartesianProduct(); + private static final CartesianProduct INSTANCE = new CartesianProduct<>(); private CartesianProduct() { } @@ -33,7 +33,7 @@ public Iterable> apply(Iterable as, Iterable bs) { @SuppressWarnings("unchecked") public static CartesianProduct cartesianProduct() { - return INSTANCE; + return (CartesianProduct) INSTANCE; } public static Fn1, Iterable>> cartesianProduct(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java index 132dec5c7..de9bd9e4e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java @@ -18,7 +18,7 @@ */ public final class CmpEq> implements BiPredicate { - private static final CmpEq INSTANCE = new CmpEq(); + private static final CmpEq INSTANCE = new CmpEq<>(); private CmpEq() { } @@ -30,7 +30,7 @@ public Boolean apply(A x, A y) { @SuppressWarnings("unchecked") public static > CmpEq cmpEq() { - return INSTANCE; + return (CmpEq) INSTANCE; } public static > Predicate cmpEq(A x) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java index bee418871..c69d18ddd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java @@ -11,7 +11,7 @@ */ public final class Cons implements Fn2, Iterable> { - private static final Cons INSTANCE = new Cons(); + private static final Cons INSTANCE = new Cons<>(); private Cons() { } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java index 777279597..384b62175 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java @@ -23,7 +23,7 @@ */ public final class Difference implements Fn2, Iterable, Iterable> { - private static final Difference INSTANCE = new Difference(); + private static final Difference INSTANCE = new Difference<>(); private Difference() { } @@ -45,7 +45,7 @@ public Iterable apply(Iterable xs, Iterable ys) { @SuppressWarnings("unchecked") public static Difference difference() { - return INSTANCE; + return (Difference) INSTANCE; } public static Fn1, Iterable> difference(Iterable xs) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java index c286d2da6..291324bdf 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java @@ -15,7 +15,7 @@ */ public final class Drop implements Fn2, Iterable> { - private static final Drop INSTANCE = new Drop(); + private static final Drop INSTANCE = new Drop<>(); private Drop() { } @@ -27,7 +27,7 @@ public Iterable apply(Integer n, Iterable as) { @SuppressWarnings("unchecked") public static Drop drop() { - return INSTANCE; + return (Drop) INSTANCE; } public static Fn1, Iterable> drop(int n) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java index 560f35c5c..edd8e45fb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java @@ -18,7 +18,7 @@ public final class DropWhile implements Fn2, Iterable, Iterable> { - private static final DropWhile INSTANCE = new DropWhile(); + private static final DropWhile INSTANCE = new DropWhile<>(); private DropWhile() { } @@ -30,7 +30,7 @@ public Iterable apply(Function predicate, Itera @SuppressWarnings("unchecked") public static DropWhile dropWhile() { - return INSTANCE; + return (DropWhile) INSTANCE; } public static Fn1, Iterable> dropWhile(Function predicate) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java index 83cce842c..126d26072 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java @@ -10,7 +10,7 @@ */ public final class Eq implements BiPredicate { - private static final Eq INSTANCE = new Eq(); + private static final Eq INSTANCE = new Eq<>(); private Eq() { } @@ -22,7 +22,7 @@ public Boolean apply(A x, A y) { @SuppressWarnings("unchecked") public static Eq eq() { - return INSTANCE; + return (Eq) INSTANCE; } public static Predicate eq(A x) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java index fd0c70e7a..8e208ac1b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java @@ -16,7 +16,7 @@ */ public final class Filter implements Fn2, Iterable, Iterable> { - private static final Filter INSTANCE = new Filter(); + private static final Filter INSTANCE = new Filter<>(); private Filter() { } @@ -28,7 +28,7 @@ public Iterable apply(Function predicate, Itera @SuppressWarnings("unchecked") public static Filter filter() { - return INSTANCE; + return (Filter) INSTANCE; } public static Fn1, Iterable> filter(Function predicate) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java index 716a4f3e8..2ddf0c8be 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java @@ -20,7 +20,7 @@ */ public final class Find implements Fn2, Iterable, Maybe> { - private static final Find INSTANCE = new Find(); + private static final Find INSTANCE = new Find<>(); private Find() { } @@ -32,7 +32,7 @@ public Maybe apply(Function predicate, Iterable @SuppressWarnings("unchecked") public static Find find() { - return INSTANCE; + return (Find) INSTANCE; } public static Fn1, Maybe> find(Function predicate) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java index 85cd2018c..7d99e7bc1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java @@ -17,7 +17,7 @@ */ public final class GT> implements BiPredicate { - private static final GT INSTANCE = new GT(); + private static final GT INSTANCE = new GT<>(); private GT() { } @@ -29,7 +29,7 @@ public Boolean apply(A y, A x) { @SuppressWarnings("unchecked") public static > GT gt() { - return INSTANCE; + return (GT) INSTANCE; } public static > Predicate gt(A y) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java index a0203984d..5304755de 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java @@ -17,7 +17,7 @@ */ public final class GTE> implements BiPredicate { - private static final GTE INSTANCE = new GTE(); + private static final GTE INSTANCE = new GTE<>(); private GTE() { } @@ -29,7 +29,7 @@ public Boolean apply(A y, A x) { @SuppressWarnings("unchecked") public static > GTE gte() { - return INSTANCE; + return (GTE) INSTANCE; } public static > Predicate gte(A y) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java index 1ef163a74..1e85a30ab 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java @@ -22,7 +22,7 @@ */ public final class GroupBy implements Fn2, Iterable, Map>> { - private static final GroupBy INSTANCE = new GroupBy(); + private static final GroupBy INSTANCE = new GroupBy<>(); private GroupBy() { } @@ -37,7 +37,7 @@ public Map> apply(Function keyFn, Iterable @SuppressWarnings("unchecked") public static GroupBy groupBy() { - return INSTANCE; + return (GroupBy) INSTANCE; } public static Fn1, Map>> groupBy(Function keyFn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java index da93304c3..410e5745c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java @@ -14,7 +14,7 @@ */ public final class InGroupsOf implements Fn2, Iterable>> { - private static final InGroupsOf INSTANCE = new InGroupsOf(); + private static final InGroupsOf INSTANCE = new InGroupsOf<>(); private InGroupsOf() { } @@ -26,7 +26,7 @@ public Iterable> apply(Integer k, Iterable as) { @SuppressWarnings("unchecked") public static InGroupsOf inGroupsOf() { - return INSTANCE; + return (InGroupsOf) INSTANCE; } public static Fn1, Iterable>> inGroupsOf(Integer k) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java index 178b7be8c..1a061a471 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java @@ -18,7 +18,7 @@ */ public final class Intersection implements Fn2, Iterable, Iterable> { - private static final Intersection INSTANCE = new Intersection(); + private static final Intersection INSTANCE = new Intersection<>(); private Intersection() { } @@ -30,7 +30,7 @@ public Iterable apply(Iterable xs, Iterable ys) { @SuppressWarnings("unchecked") public static Intersection intersection() { - return INSTANCE; + return (Intersection) INSTANCE; } public static Fn1, Iterable> intersection(Iterable xs) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java index 68d7bc54d..27c5cf02e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java @@ -15,7 +15,7 @@ */ public final class Intersperse implements Fn2, Iterable> { - private static final Intersperse INSTANCE = new Intersperse(); + private static final Intersperse INSTANCE = new Intersperse<>(); private Intersperse() { } @@ -27,7 +27,7 @@ public Iterable apply(A a, Iterable as) { @SuppressWarnings("unchecked") public static Intersperse intersperse() { - return INSTANCE; + return (Intersperse) INSTANCE; } public static Fn1, Iterable> intersperse(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java index 5fa399bb1..75e7b4c24 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java @@ -16,7 +16,7 @@ */ public final class Into implements Fn2, Map.Entry, C> { - private static final Into INSTANCE = new Into(); + private static final Into INSTANCE = new Into<>(); private Into() { } @@ -28,7 +28,7 @@ public C apply(BiFunction fn, Map.Entry @SuppressWarnings("unchecked") public static Into into() { - return INSTANCE; + return (Into) INSTANCE; } public static Fn1, C> into( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java index e965ee544..a230d94b2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java @@ -15,7 +15,7 @@ */ public final class Into1 implements Fn2, SingletonHList, B> { - private static final Into1 INSTANCE = new Into1(); + private static final Into1 INSTANCE = new Into1<>(); @Override public B apply(Function fn, SingletonHList singletonHList) { @@ -24,7 +24,7 @@ public B apply(Function fn, SingletonHList singletonH @SuppressWarnings("unchecked") public static Into1 into1() { - return INSTANCE; + return (Into1) INSTANCE; } public static Fn1, B> into1(Function fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java index 9572d3f8d..f9ed9a6cc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java @@ -16,7 +16,7 @@ */ public final class Into3 implements Fn2, Product3, D> { - private static final Into3 INSTANCE = new Into3(); + private static final Into3 INSTANCE = new Into3<>(); @Override public D apply(Fn3 fn, Product3 product) { @@ -25,7 +25,7 @@ public D apply(Fn3 fn, Product3 Into3 into3() { - return INSTANCE; + return (Into3) INSTANCE; } public static Fn1, D> into3(Fn3 fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java index 9cd0f37e0..3544516eb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java @@ -17,7 +17,7 @@ */ public final class Into4 implements Fn2, Product4, E> { - private static final Into4 INSTANCE = new Into4(); + private static final Into4 INSTANCE = new Into4<>(); @Override public E apply(Fn4 fn, Product4 product) { @@ -26,7 +26,7 @@ public E apply(Fn4 fn, @SuppressWarnings("unchecked") public static Into4 into4() { - return INSTANCE; + return (Into4) INSTANCE; } public static Fn1, E> into4( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java index a55294f10..e59852f62 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java @@ -18,7 +18,7 @@ */ public final class Into5 implements Fn2, Product5, F> { - private static final Into5 INSTANCE = new Into5(); + private static final Into5 INSTANCE = new Into5<>(); @Override public F apply(Fn5 fn, @@ -28,7 +28,7 @@ public F apply(Fn5 Into5 into5() { - return INSTANCE; + return (Into5) INSTANCE; } public static Fn1, F> into5( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java index 9caf25a5b..1b4180688 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java @@ -20,7 +20,7 @@ */ public final class Into6 implements Fn2, Product6, G> { - private static final Into6 INSTANCE = new Into6(); + private static final Into6 INSTANCE = new Into6<>(); @Override public G apply(Fn6 fn, @@ -30,7 +30,7 @@ public G apply(Fn6 Into6 into6() { - return INSTANCE; + return (Into6) INSTANCE; } public static Fn1, G> into6( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java index 3ea4d0ebd..fe4b0d7e4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java @@ -21,7 +21,7 @@ */ public final class Into7 implements Fn2, Product7, H> { - private static final Into7 INSTANCE = new Into7(); + private static final Into7 INSTANCE = new Into7<>(); @Override public H apply(Fn7 fn, @@ -31,7 +31,7 @@ public H apply(Fn7 Into7 into7() { - return INSTANCE; + return (Into7) INSTANCE; } public static Fn1, H> into7( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java index a04d17660..d41c7ff75 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java @@ -22,7 +22,7 @@ */ public final class Into8 implements Fn2, Product8, I> { - private static final Into8 INSTANCE = new Into8(); + private static final Into8 INSTANCE = new Into8<>(); @Override public I apply( @@ -33,7 +33,7 @@ public I apply( @SuppressWarnings("unchecked") public static Into8 into8() { - return INSTANCE; + return (Into8) INSTANCE; } public static Fn1, I> into8( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java index d948bb12f..596bea845 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java @@ -18,7 +18,7 @@ */ public final class Iterate implements Fn2, A, Iterable> { - private static final Iterate INSTANCE = new Iterate(); + private static final Iterate INSTANCE = new Iterate<>(); private Iterate() { } @@ -30,7 +30,7 @@ public Iterable apply(Function fn, A seed) { @SuppressWarnings("unchecked") public static Iterate iterate() { - return INSTANCE; + return (Iterate) INSTANCE; } public static Fn1> iterate(Function fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java index 68f9fe1b2..b5ccf4e23 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java @@ -17,7 +17,7 @@ */ public final class LT> implements BiPredicate { - private static final LT INSTANCE = new LT(); + private static final LT INSTANCE = new LT<>(); private LT() { } @@ -29,7 +29,7 @@ public Boolean apply(A y, A x) { @SuppressWarnings("unchecked") public static > LT lt() { - return INSTANCE; + return (LT) INSTANCE; } public static > Predicate lt(A y) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java index 72bdc97ad..4287229c2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java @@ -17,7 +17,7 @@ */ public final class LTE> implements BiPredicate { - private static final LTE INSTANCE = new LTE(); + private static final LTE INSTANCE = new LTE<>(); private LTE() { } @@ -29,7 +29,7 @@ public Boolean apply(A y, A x) { @SuppressWarnings("unchecked") public static > LTE lte() { - return INSTANCE; + return (LTE) INSTANCE; } public static > Predicate lte(A y) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java index ef94c372a..686c521b0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java @@ -27,7 +27,7 @@ */ public final class MagnetizeBy implements Fn2, Iterable, Iterable>> { - private static final MagnetizeBy INSTANCE = new MagnetizeBy(); + private static final MagnetizeBy INSTANCE = new MagnetizeBy<>(); private MagnetizeBy() { } @@ -45,7 +45,7 @@ public Iterable> apply(BiFunction MagnetizeBy magnetizeBy() { - return INSTANCE; + return (MagnetizeBy) INSTANCE; } public static Fn1, Iterable>> magnetizeBy( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java index 2b48c2a07..bc0085cf7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java @@ -15,7 +15,7 @@ */ public final class Map implements Fn2, Iterable, Iterable> { - private static final Map INSTANCE = new Map(); + private static final Map INSTANCE = new Map<>(); private Map() { } @@ -27,7 +27,7 @@ public Iterable apply(Function fn, Iterable as) { @SuppressWarnings("unchecked") public static Map map() { - return INSTANCE; + return (Map) INSTANCE; } public static Fn1, Iterable> map(Function fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java index 2c2317470..4a02e0ed5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java @@ -16,7 +16,7 @@ */ public final class Partial2 implements Fn2, A, Fn1> { - private static final Partial2 INSTANCE = new Partial2(); + private static final Partial2 INSTANCE = new Partial2<>(); private Partial2() { } @@ -28,7 +28,7 @@ public Fn1 apply(BiFunction fn, A a) { @SuppressWarnings("unchecked") public static Partial2, A, Fn1> partial2() { - return INSTANCE; + return (Partial2, A, Fn1>) INSTANCE; } public static Fn1> partial2(BiFunction fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java index 8473a356b..df9b804a5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java @@ -16,7 +16,7 @@ */ public final class Partial3 implements Fn2, A, Fn2> { - private static final Partial3 INSTANCE = new Partial3(); + private static final Partial3 INSTANCE = new Partial3<>(); private Partial3() { } @@ -28,7 +28,7 @@ public Fn2 apply(Fn3 fn, A a) { @SuppressWarnings("unchecked") public static Partial3 partial3() { - return INSTANCE; + return (Partial3) INSTANCE; } public static Fn1> partial3(Fn3 fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java index 5a9a17148..368dfb0bb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java @@ -26,7 +26,7 @@ */ public final class Partition implements Fn2>, Iterable, Tuple2, Iterable>> { - private static final Partition INSTANCE = new Partition(); + private static final Partition INSTANCE = new Partition<>(); private Partition() { } @@ -42,7 +42,7 @@ public Tuple2, Iterable> apply(Function Partition partition() { - return INSTANCE; + return (Partition) INSTANCE; } public static Fn1, Tuple2, Iterable>> partition( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java index 59ee59cda..bd86c6856 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java @@ -15,7 +15,7 @@ * @param the functor type */ public final class Peek> implements Fn2, FA, FA> { - private static final Peek INSTANCE = new Peek<>(); + private static final Peek INSTANCE = new Peek<>(); private Peek() { } @@ -31,7 +31,7 @@ public FA apply(Consumer consumer, FA fa) { @SuppressWarnings("unchecked") public static > Peek peek() { - return INSTANCE; + return (Peek) INSTANCE; } public static > Fn1 peek(Consumer consumer) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java index d544ac7d7..e228293e5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java @@ -19,7 +19,7 @@ * @param the bifunctor type */ public final class Peek2> implements Fn3, Consumer, FAB, FAB> { - private static final Peek2 INSTANCE = new Peek2<>(); + private static final Peek2 INSTANCE = new Peek2<>(); private Peek2() { } @@ -38,7 +38,7 @@ public FAB apply(Consumer aConsumer, Consumer bConsumer, F @SuppressWarnings("unchecked") public static > Peek2 peek2() { - return INSTANCE; + return (Peek2) INSTANCE; } public static > Fn2, FAB, FAB> peek2( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java index 4c7f26f2a..94ebd2c78 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java @@ -13,7 +13,7 @@ */ public final class PrependAll implements Fn2, Iterable> { - private static final PrependAll INSTANCE = new PrependAll(); + private static final PrependAll INSTANCE = new PrependAll<>(); private PrependAll() { } @@ -25,7 +25,7 @@ public Iterable apply(A a, Iterable as) { @SuppressWarnings("unchecked") public static PrependAll prependAll() { - return INSTANCE; + return (PrependAll) INSTANCE; } public static Fn1, Iterable> prependAll(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java index c25b988a4..150206f61 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java @@ -27,7 +27,7 @@ */ public final class ReduceLeft implements Fn2, Iterable, Maybe> { - private static final ReduceLeft INSTANCE = new ReduceLeft(); + private static final ReduceLeft INSTANCE = new ReduceLeft<>(); private ReduceLeft() { } @@ -40,7 +40,7 @@ public Maybe apply(BiFunction fn, Iterable @SuppressWarnings("unchecked") public static ReduceLeft reduceLeft() { - return INSTANCE; + return (ReduceLeft) INSTANCE; } public static Fn1, Maybe> reduceLeft(BiFunction fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java index 432ac0f56..14a39b20a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java @@ -25,7 +25,7 @@ */ public final class ReduceRight implements Fn2, Iterable, Maybe> { - private static final ReduceRight INSTANCE = new ReduceRight(); + private static final ReduceRight INSTANCE = new ReduceRight<>(); private ReduceRight() { } @@ -37,7 +37,7 @@ public final Maybe apply(BiFunction fn, It @SuppressWarnings("unchecked") public static ReduceRight reduceRight() { - return INSTANCE; + return (ReduceRight) INSTANCE; } public static Fn1, Maybe> reduceRight(BiFunction fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java index d810f4938..c310ae8ec 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java @@ -13,7 +13,7 @@ */ public final class Replicate implements Fn2> { - private static final Replicate INSTANCE = new Replicate(); + private static final Replicate INSTANCE = new Replicate<>(); private Replicate() { } @@ -25,7 +25,7 @@ public Iterable apply(Integer n, A a) { @SuppressWarnings("unchecked") public static Replicate replicate() { - return INSTANCE; + return (Replicate) INSTANCE; } public static Fn1> replicate(Integer n) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java index 36b394970..fffe9b580 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java @@ -30,13 +30,13 @@ * @param the concrete parametrized output Applicative type * @param the concrete parametrized input Traversable type */ -public final class Sequence, Trav extends Traversable, AppA extends Applicative, TravA extends Traversable, AppTrav extends Applicative, TravApp extends Traversable> implements Fn2, AppTrav> { - private static final Sequence INSTANCE = new Sequence(); + private static final Sequence INSTANCE = new Sequence<>(); private Sequence() { } @@ -47,15 +47,15 @@ public AppTrav apply(TravApp traversable, Function pur } @SuppressWarnings("unchecked") - public static , Trav extends Traversable, AppA extends Applicative, TravA extends Traversable, AppTrav extends Applicative, TravApp extends Traversable> Sequence sequence() { - return INSTANCE; + return (Sequence) INSTANCE; } - public static , Trav extends Traversable, AppA extends Applicative, TravA extends Traversable, AppTrav extends Applicative, @@ -64,7 +64,7 @@ TravApp extends Traversable> Sequencesequence().apply(traversable); } - public static , Trav extends Traversable, TravA extends Traversable, AppA extends Applicative, AppTrav extends Applicative, @@ -74,27 +74,27 @@ TravApp extends Traversable> AppTrav sequence(TravApp traversable, } @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) - public static , AppIterable extends Applicative, App>, IterableApp extends Iterable> + public static , AppA extends Applicative, AppIterable extends Applicative, App>, IterableApp extends Iterable> Fn1, ? extends AppIterable>, AppIterable> sequence(IterableApp iterableApp) { - return pure -> (AppIterable) Sequence., AppA, Applicative, App>, LambdaIterable>sequence( + return pure -> (AppIterable) Sequence., LambdaIterable, AppA, Applicative, App>, LambdaIterable>sequence( LambdaIterable.wrap(iterableApp), x -> pure.apply(x.unwrap()).fmap(LambdaIterable::wrap)) .fmap(LambdaIterable::unwrap); } - public static , AppIterable extends Applicative, App>, IterableApp extends Iterable> + public static , AppA extends Applicative, AppIterable extends Applicative, App>, IterableApp extends Iterable> AppIterable sequence(IterableApp iterableApp, Function, ? extends AppIterable> pure) { return Sequence.sequence(iterableApp).apply(pure); } @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) - public static , AppMap extends Applicative, App>, MapApp extends Map> + public static , AppB extends Applicative, AppMap extends Applicative, App>, MapApp extends Map> Fn1, ? extends AppMap>, AppMap> sequence(MapApp mapApp) { return pure -> (AppMap) Sequence., LambdaMap, AppB, Applicative, App>, LambdaMap>sequence( LambdaMap.wrap(mapApp), x -> pure.apply(x.unwrap()).fmap(LambdaMap::wrap)) .fmap(LambdaMap::unwrap); } - public static , AppMap extends Applicative, App>, MapApp extends Map> + public static , AppB extends Applicative, AppMap extends Applicative, App>, MapApp extends Map> AppMap sequence(MapApp mapApp, Function, ? extends AppMap> pure) { return Sequence.sequence(mapApp).apply(pure); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java index 337d59788..caec56faa 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java @@ -21,7 +21,7 @@ */ public final class Slide implements Fn2, Iterable>> { - private static final Slide INSTANCE = new Slide<>(); + private static final Slide INSTANCE = new Slide<>(); private Slide() { } @@ -36,7 +36,7 @@ public Iterable> apply(Integer k, Iterable as) { @SuppressWarnings("unchecked") public static Slide slide() { - return INSTANCE; + return (Slide) INSTANCE; } public static Fn1, Iterable>> slide(Integer k) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java index 6437c0c57..dbf151ab5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java @@ -15,7 +15,7 @@ */ public final class Snoc implements Fn2, Iterable> { - private static final Snoc INSTANCE = new Snoc(); + private static final Snoc INSTANCE = new Snoc<>(); private Snoc() { } @@ -27,7 +27,7 @@ public Iterable apply(A a, Iterable as) { @SuppressWarnings("unchecked") public static Snoc snoc() { - return INSTANCE; + return (Snoc) INSTANCE; } public static Fn1, Iterable> snoc(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java index b92628141..a5c52ed58 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java @@ -22,7 +22,7 @@ */ public final class SortBy> implements Fn2, Iterable, List> { - private static final SortBy INSTANCE = new SortBy(); + private static final SortBy INSTANCE = new SortBy<>(); private SortBy() { } @@ -34,7 +34,7 @@ public List apply(Function fn, Iterable as) { @SuppressWarnings("unchecked") public static > SortBy sortBy() { - return INSTANCE; + return (SortBy) INSTANCE; } public static > Fn1, List> sortBy( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java index 813fb2e53..4062d3ebe 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java @@ -21,7 +21,7 @@ */ public final class SortWith implements Fn2, Iterable, List> { - private static final SortWith INSTANCE = new SortWith(); + private static final SortWith INSTANCE = new SortWith<>(); private SortWith() { } @@ -35,7 +35,7 @@ public List apply(Comparator comparator, Iterable as) { @SuppressWarnings("unchecked") public static SortWith sortWith() { - return INSTANCE; + return (SortWith) INSTANCE; } public static Fn1, List> sortWith(Comparator comparator) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java index aea792d08..3450a9c49 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java @@ -17,7 +17,7 @@ */ public final class Span implements Fn2, Iterable, Tuple2, Iterable>> { - private static final Span INSTANCE = new Span(); + private static final Span INSTANCE = new Span<>(); private Span() { } @@ -29,7 +29,7 @@ public Tuple2, Iterable> apply(Function Span span() { - return INSTANCE; + return (Span) INSTANCE; } public static Fn1, Tuple2, Iterable>> span( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java index ed10f75bc..86c417a6d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java @@ -15,7 +15,7 @@ */ public final class Take implements Fn2, Iterable> { - private static final Take INSTANCE = new Take(); + private static final Take INSTANCE = new Take<>(); private Take() { } @@ -27,7 +27,7 @@ public Iterable apply(Integer n, Iterable as) { @SuppressWarnings("unchecked") public static Take take() { - return INSTANCE; + return (Take) INSTANCE; } public static Fn1, Iterable> take(int n) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java index 8285d953c..29863e2bc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java @@ -17,7 +17,7 @@ */ public final class TakeWhile implements Fn2, Iterable, Iterable> { - private static final TakeWhile INSTANCE = new TakeWhile(); + private static final TakeWhile INSTANCE = new TakeWhile<>(); private TakeWhile() { } @@ -29,7 +29,7 @@ public Iterable apply(Function predicate, Itera @SuppressWarnings("unchecked") public static TakeWhile takeWhile() { - return INSTANCE; + return (TakeWhile) INSTANCE; } public static Fn1, Iterable> takeWhile(Function predicate) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java index e12ae85b1..4b41af1b8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java @@ -16,7 +16,7 @@ */ public final class ToArray implements Fn2, Iterable, A[]> { - private static final ToArray INSTANCE = new ToArray<>(); + private static final ToArray INSTANCE = new ToArray<>(); private ToArray() { } @@ -37,7 +37,7 @@ public A[] apply(Class arrayType, Iterable as) { @SuppressWarnings("unchecked") public static ToArray toArray() { - return INSTANCE; + return (ToArray) INSTANCE; } public static Fn1, A[]> toArray(Class arrayType) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java index b9b46b893..545682fb6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java @@ -16,7 +16,7 @@ */ public final class ToCollection> implements Fn2, Iterable, C> { - private static final ToCollection INSTANCE = new ToCollection(); + private static final ToCollection INSTANCE = new ToCollection<>(); private ToCollection() { } @@ -30,7 +30,7 @@ public C apply(Supplier cSupplier, Iterable as) { @SuppressWarnings("unchecked") public static > ToCollection toCollection() { - return INSTANCE; + return (ToCollection) INSTANCE; } public static > Fn1, C> toCollection(Supplier cSupplier) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java index 1522720aa..2b21f5268 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java @@ -19,7 +19,7 @@ */ public final class ToMap> implements Fn2, Iterable>, M> { - private static final ToMap INSTANCE = new ToMap<>(); + private static final ToMap INSTANCE = new ToMap<>(); private ToMap() { } @@ -34,7 +34,7 @@ public M apply(Supplier mSupplier, Iterable> entrie @SuppressWarnings("unchecked") public static > ToMap toMap() { - return INSTANCE; + return (ToMap) INSTANCE; } public static > Fn1>, M> toMap(Supplier mSupplier) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java index de1b4a283..6b69f4441 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java @@ -15,7 +15,7 @@ */ public final class Tupler2 implements Fn2> { - private static final Tupler2 INSTANCE = new Tupler2(); + private static final Tupler2 INSTANCE = new Tupler2<>(); private Tupler2() { } @@ -27,7 +27,7 @@ public Tuple2 apply(A a, B b) { @SuppressWarnings("unchecked") public static Tupler2 tupler() { - return INSTANCE; + return (Tupler2) INSTANCE; } public static Fn1> tupler(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java index 9a2cd1b15..efb79a76c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java @@ -31,7 +31,7 @@ */ public final class Unfoldr implements Fn2>>, B, Iterable> { - private static final Unfoldr INSTANCE = new Unfoldr(); + private static final Unfoldr INSTANCE = new Unfoldr<>(); private Unfoldr() { } @@ -43,7 +43,7 @@ public Iterable apply(Function>> fn, B b) { @SuppressWarnings("unchecked") public static Unfoldr unfoldr() { - return INSTANCE; + return (Unfoldr) INSTANCE; } public static Fn1> unfoldr(Function>> fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java index 323f00e02..3e6ba39eb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java @@ -17,7 +17,7 @@ */ public final class Zip implements Fn2, Iterable, Iterable>> { - private static final Zip INSTANCE = new Zip(); + private static final Zip INSTANCE = new Zip<>(); private Zip() { } @@ -29,7 +29,7 @@ public Iterable> apply(Iterable as, Iterable bs) { @SuppressWarnings("unchecked") public static Zip zip() { - return INSTANCE; + return (Zip) INSTANCE; } public static Fn1, Iterable>> zip(Iterable as) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java index 70dac2bce..451addf5c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java @@ -14,7 +14,7 @@ */ public final class Between> implements Fn3 { - private static final Between INSTANCE = new Between<>(); + private static final Between INSTANCE = new Between<>(); private Between() { } @@ -26,7 +26,7 @@ public Boolean apply(A lower, A upper, A a) { @SuppressWarnings("unchecked") public static > Between between() { - return INSTANCE; + return (Between) INSTANCE; } public static > BiPredicate between(A lower) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java index 62d0c21de..20de04a77 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java @@ -17,7 +17,7 @@ */ public final class Clamp> implements Fn3 { - private static final Clamp INSTANCE = new Clamp<>(); + private static final Clamp INSTANCE = new Clamp<>(); private Clamp() { } @@ -29,7 +29,7 @@ public A apply(A lower, A upper, A a) { @SuppressWarnings("unchecked") public static > Clamp clamp() { - return INSTANCE; + return (Clamp) INSTANCE; } public static > Fn2 clamp(A lower) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java index 156c51413..5ef1382f7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java @@ -20,7 +20,7 @@ */ public final class CmpEqBy> implements Fn3, A, A, Boolean> { - private static final CmpEqBy INSTANCE = new CmpEqBy(); + private static final CmpEqBy INSTANCE = new CmpEqBy<>(); private CmpEqBy() { } @@ -42,7 +42,7 @@ public Predicate apply(Function compareFn, A x) { @SuppressWarnings("unchecked") public static > CmpEqBy cmpEqBy() { - return INSTANCE; + return (CmpEqBy) INSTANCE; } public static > BiPredicate cmpEqBy(Function compareFn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java index 17fb496d1..ec0ad331e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java @@ -22,7 +22,7 @@ */ public final class FoldLeft implements Fn3, B, Iterable, B> { - private static final FoldLeft INSTANCE = new FoldLeft(); + private static final FoldLeft INSTANCE = new FoldLeft<>(); private FoldLeft() { } @@ -37,7 +37,7 @@ public B apply(BiFunction fn, B acc, Iterable @SuppressWarnings("unchecked") public static FoldLeft foldLeft() { - return INSTANCE; + return (FoldLeft) INSTANCE; } public static Fn2, B> foldLeft(BiFunction fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java index d79910faa..6dc2ddef1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java @@ -19,7 +19,7 @@ */ public final class GTBy> implements Fn3, A, A, Boolean> { - private static final GTBy INSTANCE = new GTBy(); + private static final GTBy INSTANCE = new GTBy<>(); private GTBy() { } @@ -41,7 +41,7 @@ public Predicate apply(Function compareFn, A x) { @SuppressWarnings("unchecked") public static > GTBy gtBy() { - return INSTANCE; + return (GTBy) INSTANCE; } public static > BiPredicate gtBy(Function fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java index f61fcb4c6..830eacb69 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java @@ -22,7 +22,7 @@ */ public final class GTEBy> implements Fn3, A, A, Boolean> { - private static final GTEBy INSTANCE = new GTEBy(); + private static final GTEBy INSTANCE = new GTEBy<>(); private GTEBy() { } @@ -44,7 +44,7 @@ public Predicate apply(Function compareFn, A y) { @SuppressWarnings("unchecked") public static > GTEBy gteBy() { - return INSTANCE; + return (GTEBy) INSTANCE; } public static > BiPredicate gteBy(Function fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java index 632cc9da0..b09fb69a2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java @@ -19,7 +19,7 @@ */ public final class LTBy> implements Fn3, A, A, Boolean> { - private static final LTBy INSTANCE = new LTBy(); + private static final LTBy INSTANCE = new LTBy<>(); private LTBy() { } @@ -41,7 +41,7 @@ public Predicate apply(Function compareFn, A y) { @SuppressWarnings("unchecked") public static > LTBy ltBy() { - return INSTANCE; + return (LTBy) INSTANCE; } public static > BiPredicate ltBy(Function fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java index c001a8c89..2eb29c7e1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java @@ -22,7 +22,7 @@ */ public final class LTEBy> implements Fn3, A, A, Boolean> { - private static final LTEBy INSTANCE = new LTEBy(); + private static final LTEBy INSTANCE = new LTEBy<>(); private LTEBy() { } @@ -44,7 +44,7 @@ public Predicate apply(Function compareFn, A y) { @SuppressWarnings("unchecked") public static > LTEBy lteBy() { - return INSTANCE; + return (LTEBy) INSTANCE; } public static > BiPredicate lteBy(Function fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java index 7ba773691..55d58fb6a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java @@ -20,12 +20,13 @@ * @param the inferred applicative return type * @see Applicative#zip(Applicative) */ -public final class LiftA2, AppA extends Applicative, AppB extends Applicative, - AppC extends Applicative> implements Fn3, AppA, AppB, AppC> { + AppC extends Applicative> implements + Fn3, AppA, AppB, AppC> { - private static final LiftA2 INSTANCE = new LiftA2(); + private static final LiftA2 INSTANCE = new LiftA2<>(); private LiftA2() { } @@ -36,25 +37,31 @@ public AppC apply(BiFunction fn, AppA appA, A } @SuppressWarnings("unchecked") - public static , AppB extends Applicative, AppC extends Applicative> LiftA2 liftA2() { - return INSTANCE; + public static , AppA extends Applicative, + AppB extends Applicative, + AppC extends Applicative> LiftA2 liftA2() { + return (LiftA2) INSTANCE; } - public static , AppB extends Applicative, AppC extends Applicative> Fn2 liftA2( + public static , AppA extends Applicative, + AppB extends Applicative, + AppC extends Applicative> Fn2 liftA2( BiFunction fn) { return LiftA2.liftA2().apply(fn); } - public static , AppB extends Applicative, AppC extends Applicative> Fn1 liftA2( - BiFunction fn, - AppA appA) { + public static , AppA extends Applicative, + AppB extends Applicative, + AppC extends Applicative> Fn1 liftA2(BiFunction fn, + AppA appA) { return LiftA2.liftA2(fn).apply(appA); } - public static , AppB extends Applicative, AppC extends Applicative> AppC liftA2( - BiFunction fn, - AppA appA, - AppB appB) { + public static , AppA extends Applicative, + AppB extends Applicative, + AppC extends Applicative> AppC liftA2(BiFunction fn, + AppA appA, + AppB appB) { return LiftA2.liftA2(fn, appA).apply(appB); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java index 9cc780a15..400f1d267 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java @@ -20,7 +20,7 @@ */ public final class ScanLeft implements Fn3, B, Iterable, Iterable> { - private static final ScanLeft INSTANCE = new ScanLeft(); + private static final ScanLeft INSTANCE = new ScanLeft<>(); private ScanLeft() { } @@ -32,7 +32,7 @@ public Iterable apply(BiFunction fn, B b, @SuppressWarnings("unchecked") public static ScanLeft scanLeft() { - return INSTANCE; + return (ScanLeft) INSTANCE; } public static Fn2, Iterable> scanLeft(BiFunction fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java index cdf33a8d7..a12ab841f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java @@ -22,7 +22,7 @@ */ public final class Times implements Fn3, A, A> { - private static final Times INSTANCE = new Times(); + private static final Times INSTANCE = new Times<>(); private Times() { } @@ -37,7 +37,7 @@ public A apply(Integer n, Function fn, A a) { @SuppressWarnings("unchecked") public static Times times() { - return INSTANCE; + return (Times) INSTANCE; } public static Fn2, A, A> times(Integer n) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java index 75266b884..4341ca32f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java @@ -19,7 +19,7 @@ */ public final class ZipWith implements Fn3, Iterable, Iterable, Iterable> { - private static final ZipWith INSTANCE = new ZipWith(); + private static final ZipWith INSTANCE = new ZipWith<>(); private ZipWith() { } @@ -31,7 +31,7 @@ public Iterable apply(BiFunction zipper, I @SuppressWarnings("unchecked") public static ZipWith zipWith() { - return INSTANCE; + return (ZipWith) INSTANCE; } public static Fn2, Iterable, Iterable> zipWith( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java index d67440595..53d40315d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java @@ -9,7 +9,7 @@ public final class IfThenElse implements Fn4, Function, Function, A, B> { - private static final IfThenElse INSTANCE = new IfThenElse(); + private static final IfThenElse INSTANCE = new IfThenElse<>(); private IfThenElse() { } @@ -22,7 +22,7 @@ public B apply(Function predicate, Function IfThenElse ifThenElse() { - return INSTANCE; + return (IfThenElse) INSTANCE; } public static Fn3, Function, A, B> ifThenElse( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java index a34a1aaae..43c9bc018 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java @@ -22,13 +22,13 @@ * @see Applicative#zip(Applicative) */ public final class LiftA3, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative> implements Fn4, AppA, AppB, AppC, AppD> { - private static final LiftA3 INSTANCE = new LiftA3(); + private static final LiftA3 INSTANCE = new LiftA3<>(); private LiftA3() { } @@ -40,16 +40,16 @@ public AppD apply(Fn3 fn, AppA appA, AppB appB, AppC appC) { @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative> LiftA3 liftA3() { - return INSTANCE; + return (LiftA3) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -58,7 +58,7 @@ AppD extends Applicative> Fn3 liftA3(Fn3, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -67,7 +67,7 @@ AppD extends Applicative> Fn2 liftA3(Fn3 f } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -76,7 +76,7 @@ AppD extends Applicative> Fn1 liftA3(Fn3 fn, App } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java index 4c7ad843e..970b61dfb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java @@ -47,7 +47,7 @@ */ public final class RateLimit implements Fn4, Long, Duration, Iterable, Iterable> { - private static final RateLimit INSTANCE = new RateLimit(); + private static final RateLimit INSTANCE = new RateLimit<>(); private RateLimit() { } @@ -62,7 +62,7 @@ public Iterable apply(Supplier instantSupplier, Long limit, Duration @SuppressWarnings("unchecked") public static RateLimit rateLimit() { - return INSTANCE; + return (RateLimit) INSTANCE; } public static Fn3, Iterable> rateLimit(Supplier instantSupplier) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java index 099d519ca..1187aa320 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java @@ -25,14 +25,14 @@ * @see Applicative#zip(Applicative) */ public final class LiftA4, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative> implements Fn5, AppA, AppB, AppC, AppD, AppE> { - private static final LiftA4 INSTANCE = new LiftA4(); + private static final LiftA4 INSTANCE = new LiftA4<>(); private LiftA4() { } @@ -44,17 +44,17 @@ public AppE apply(Fn4 fn, AppA appA, AppB appB, AppC appC, AppD a @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative> LiftA4 liftA4() { - return INSTANCE; + return (LiftA4) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -64,7 +64,7 @@ AppE extends Applicative> Fn4 liftA4(Fn4, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -74,7 +74,7 @@ AppE extends Applicative> Fn3 liftA4(Fn4, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -85,7 +85,7 @@ AppE extends Applicative> Fn2 liftA4(Fn4, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -96,7 +96,7 @@ AppE extends Applicative> Fn1 liftA4(Fn4 fn, } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java index f32d44569..24d83bca2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java @@ -28,7 +28,7 @@ * @see Applicative#zip(Applicative) */ public final class LiftA5, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -36,7 +36,7 @@ public final class LiftA5, AppF extends Applicative> implements Fn6, AppA, AppB, AppC, AppD, AppE, AppF> { - private static final LiftA5 INSTANCE = new LiftA5(); + private static final LiftA5 INSTANCE = new LiftA5<>(); private LiftA5() { } @@ -48,18 +48,18 @@ public AppF apply(Fn5 fn, AppA appA, AppB appB, AppC appC, App @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative, AppF extends Applicative> LiftA5 liftA5() { - return INSTANCE; + return (LiftA5) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -70,7 +70,7 @@ AppF extends Applicative> Fn5 liftA5 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -82,7 +82,7 @@ AppF extends Applicative> Fn4 liftA5(Fn5, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -94,7 +94,7 @@ AppF extends Applicative> Fn3 liftA5(Fn5, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -107,7 +107,7 @@ AppF extends Applicative> Fn2 liftA5(Fn5, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -119,7 +119,7 @@ AppF extends Applicative> Fn1 liftA5(Fn5 f } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java index 72da45314..804fb7b99 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java @@ -31,16 +31,17 @@ * @see Applicative#zip(Applicative) */ public final class LiftA6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative, AppF extends Applicative, - AppG extends Applicative> implements Fn7, AppA, AppB, AppC, AppD, AppE, AppF, AppG> { + AppG extends Applicative> implements + Fn7, AppA, AppB, AppC, AppD, AppE, AppF, AppG> { - private static final LiftA6 INSTANCE = new LiftA6(); + private static final LiftA6 INSTANCE = new LiftA6<>(); private LiftA6() { } @@ -54,19 +55,20 @@ public AppG apply(Fn6 fn, AppA appA, AppB appB, AppC appC, @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, AppD extends Applicative, AppE extends Applicative, AppF extends Applicative, - AppG extends Applicative> LiftA6 liftA6() { - return INSTANCE; + AppG extends Applicative> + LiftA6 liftA6() { + return (LiftA6) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -79,7 +81,7 @@ AppG extends Applicative> Fn6 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -93,7 +95,7 @@ AppG extends Applicative> Fn5 liftA6 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -107,7 +109,7 @@ AppG extends Applicative> Fn4 liftA6(Fn6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -121,7 +123,7 @@ AppG extends Applicative> Fn3 liftA6(Fn6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -135,7 +137,7 @@ AppG extends Applicative> Fn2 liftA6(Fn6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -148,7 +150,7 @@ AppG extends Applicative> Fn1 liftA6(Fn6, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java index 6d508f06d..359801ba7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java @@ -34,7 +34,7 @@ * @see Applicative#zip(Applicative) */ public final class LiftA7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -44,7 +44,7 @@ public final class LiftA7, AppH extends Applicative> implements Fn8, AppA, AppB, AppC, AppD, AppE, AppF, AppG, AppH> { - private static final LiftA7 INSTANCE = new LiftA7(); + private static final LiftA7 INSTANCE = new LiftA7<>(); private LiftA7() { } @@ -57,7 +57,7 @@ public AppH apply(Fn7 fn, AppA appA, AppB appB, AppC app @SuppressWarnings("unchecked") public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -66,11 +66,11 @@ public AppH apply(Fn7 fn, AppA appA, AppB appB, AppC app AppF extends Applicative, AppG extends Applicative, AppH extends Applicative> LiftA7 liftA7() { - return INSTANCE; + return (LiftA7) INSTANCE; } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -84,7 +84,7 @@ AppH extends Applicative> Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -98,7 +98,7 @@ AppH extends Applicative> Fn6 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -112,7 +112,7 @@ AppH extends Applicative> Fn5 liftA7 } public static , AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -127,7 +127,7 @@ AppH extends Applicative> Fn4 liftA7(Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -142,7 +142,7 @@ AppH extends Applicative> Fn3 liftA7(Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -156,7 +156,7 @@ AppH extends Applicative> Fn2 liftA7(Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, @@ -171,7 +171,7 @@ AppH extends Applicative> Fn1 liftA7(Fn7, AppA extends Applicative, AppB extends Applicative, AppC extends Applicative, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java index 7da780a1e..afef70f6d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java @@ -80,9 +80,12 @@ public RecursiveResult discardR(Applicative> @Override @SuppressWarnings("unchecked") - public >, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { - return match(__ -> pure.apply(coerce()), b -> fn.apply(b).fmap(this::pure).fmap(Applicative::coerce).coerce()); + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { + return match(__ -> pure.apply(coerce()), + b -> fn.apply(b).fmap(this::pure).fmap(RecursiveResult::coerce).coerce()); } public static RecursiveResult recurse(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java index a4efb94cc..2d52b95d1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java @@ -22,7 +22,7 @@ */ public final class Trampoline implements Fn2>, A, B> { - private static final Trampoline INSTANCE = new Trampoline<>(); + private static final Trampoline INSTANCE = new Trampoline<>(); @Override public B apply(Function> fn, A a) { @@ -34,7 +34,7 @@ public B apply(Function> fn, A a) { @SuppressWarnings("unchecked") public static Trampoline trampoline() { - return INSTANCE; + return (Trampoline) INSTANCE; } public static Fn1 trampoline(Function> fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java index 433ef410f..9157c8e44 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java @@ -15,7 +15,7 @@ * @param the output {@link Monad} type */ @FunctionalInterface -public interface Kleisli> extends Fn1 { +public interface Kleisli, MB extends Monad> extends Fn1 { /** * Left-to-right composition of two compatible {@link Kleisli} arrows, yielding a new {@link Kleisli} arrow. @@ -83,7 +83,7 @@ default Kleisli diMapL(Function fn) { * @param the returned {@link Monad} instance * @return the function adapted as a {@link Kleisli} arrow */ - static > Kleisli kleisli( + static , MB extends Monad> Kleisli kleisli( Function fn) { return fn::apply; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java index 62c5192f4..509499536 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java @@ -8,7 +8,7 @@ * @param the argument type */ public final class Noop implements Effect { - private static final Noop INSTANCE = new Noop(); + private static final Noop INSTANCE = new Noop<>(); private Noop() { } @@ -25,6 +25,6 @@ public void accept(A a) { */ @SuppressWarnings("unchecked") public static Noop noop() { - return INSTANCE; + return (Noop) INSTANCE; } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java index 180d55c80..1f31e2ff3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java @@ -28,7 +28,7 @@ * @param The type of the parameter * @param The unification parameter to more tightly type-constrain Applicatives to themselves */ -public interface Applicative extends Functor { +public interface Applicative> extends Functor { /** * Lift the value b into this applicative functor. @@ -100,7 +100,7 @@ default Applicative discardR(Applicative appB) { * @param the concrete applicative instance to coerce this applicative to * @return the coerced applicative */ - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked"}) default > Concrete coerce() { return (Concrete) this; } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java index 695c71a8f..abdbd7024 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java @@ -17,7 +17,7 @@ * @see com.jnape.palatable.lambda.adt.hlist.Tuple2 */ @FunctionalInterface -public interface Bifunctor extends BoundedBifunctor { +public interface Bifunctor> extends BoundedBifunctor { /** * Covariantly map over the left parameter. diff --git a/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java index 02fc7775f..8096ae1cb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java @@ -16,7 +16,12 @@ * @see Bifunctor */ @FunctionalInterface -public interface BoundedBifunctor { +public interface BoundedBifunctor< + A extends ContraA, + B extends ContraB, + ContraA, + ContraB, + BF extends BoundedBifunctor> { /** * Covariantly map the left parameter into a value that is covariant to ContraA. diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java b/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java index 07d548d1a..bce1d114a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java @@ -14,7 +14,7 @@ * @param the unification parameter * @see Profunctor */ -public interface Contravariant { +public interface Contravariant> { /** * Contravariantly map A <- B. diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Functor.java b/src/main/java/com/jnape/palatable/lambda/functor/Functor.java index 769aae816..7645f1013 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Functor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Functor.java @@ -20,7 +20,7 @@ * @see com.jnape.palatable.lambda.adt.Either */ @FunctionalInterface -public interface Functor { +public interface Functor> { /** * Covariantly transmute this functor's parameter using the given mapping function. Generally this method is diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java index 0e7235b44..865f2e2d5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java @@ -22,7 +22,7 @@ * @see Lens */ @FunctionalInterface -public interface Profunctor extends Contravariant> { +public interface Profunctor> extends Contravariant> { /** * Dually map contravariantly over the left parameter and covariantly over the right parameter. This is isomorphic diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Strong.java b/src/main/java/com/jnape/palatable/lambda/functor/Strong.java index c6b4929c2..0be4c230d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Strong.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Strong.java @@ -13,7 +13,7 @@ * @param the unification parameter * @see com.jnape.palatable.lambda.functions.Fn1 */ -public interface Strong extends Profunctor { +public interface Strong> extends Profunctor { /** * Pair some type C to this profunctor's carrier types. diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index 965567501..5a08211dc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -13,7 +13,8 @@ * @param The inner applicative * @param The carrier type */ -public final class Compose implements Applicative> { +public final class Compose, G extends Applicative, A> implements + Applicative> { private final Applicative, F> fga; diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index 6ef443106..fdb81f8ef 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -17,7 +17,10 @@ * @param the left parameter type, and the type of the stored value * @param the right (phantom) parameter type */ -public final class Const implements Monad>, Bifunctor, Traversable> { +public final class Const implements + Monad>, + Bifunctor>, + Traversable> { private final A a; @@ -98,8 +101,10 @@ public Const flatMap(Function>, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return pure.apply(coerce()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java index d9781e8cc..f5beb02c9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java @@ -12,7 +12,7 @@ * * @param the value type */ -public final class Identity implements Monad, Traversable { +public final class Identity implements Monad>, Traversable> { private final A a; @@ -33,7 +33,7 @@ public A runIdentity() { * {@inheritDoc} */ @Override - public Identity flatMap(Function> f) { + public Identity flatMap(Function>> f) { return f.apply(runIdentity()).coerce(); } @@ -57,7 +57,7 @@ public Identity pure(B b) { * {@inheritDoc} */ @Override - public Identity zip(Applicative, Identity> appFn) { + public Identity zip(Applicative, Identity> appFn) { return new Identity<>(appFn.>>coerce().runIdentity().apply(a)); } @@ -65,8 +65,7 @@ public Identity zip(Applicative, Identit * {@inheritDoc} */ @Override - public Lazy> lazyZip( - Lazy, Identity>> lazyAppFn) { + public Lazy> lazyZip(Lazy, Identity>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); } @@ -74,7 +73,7 @@ public Lazy> lazyZip( * {@inheritDoc} */ @Override - public Identity discardL(Applicative appB) { + public Identity discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } @@ -82,7 +81,7 @@ public Identity discardL(Applicative appB) { * {@inheritDoc} */ @Override - public Identity discardR(Applicative appB) { + public Identity discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } @@ -91,8 +90,10 @@ public Identity discardR(Applicative appB) { */ @Override @SuppressWarnings("unchecked") - public , AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { return (AppTrav) fn.apply(runIdentity()).fmap(Identity::new); } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java b/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java index 5a734a88c..c7b109d3b 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java @@ -45,11 +45,11 @@ public A next() { @SuppressWarnings("unchecked") public static ImmutableQueue empty() { - return Empty.INSTANCE; + return (ImmutableQueue) Empty.INSTANCE; } private static final class Empty extends ImmutableQueue { - private static final Empty INSTANCE = new Empty(); + private static final Empty INSTANCE = new Empty<>(); @Override ImmutableQueue pushFront(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java b/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java index 619619efb..e2ca4a8a2 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java @@ -42,11 +42,11 @@ public A next() { @SuppressWarnings("unchecked") public static ImmutableStack empty() { - return Empty.INSTANCE; + return (ImmutableStack) Empty.INSTANCE; } private static final class Empty extends ImmutableStack { - private static final Empty INSTANCE = new Empty(); + private static final Empty INSTANCE = new Empty<>(); @Override Maybe head() { diff --git a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java b/src/main/java/com/jnape/palatable/lambda/lens/Iso.java index bff042842..7d7be3d3c 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/Iso.java @@ -52,14 +52,14 @@ @FunctionalInterface public interface Iso extends LensLike { -

, FT extends Functor, +

, F extends Functor, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply(PAFB pafb); @Override - default , FB extends Functor> FT apply( + default , FT extends Functor, FB extends Functor> FT apply( Function fn, S s) { - return this., Fn1>apply(fn1(fn)).apply(s); + return this., F, FB, FT, Fn1, Fn1>apply(fn1(fn)).apply(s); } /** @@ -70,7 +70,7 @@ default , FB extends Functor> default Lens toLens() { return new Lens() { @Override - public , FB extends Functor> FT apply( + public , FT extends Functor, FB extends Functor> FT apply( Function fn, S s) { return Iso.this.apply(fn, s); } @@ -93,7 +93,7 @@ default Iso mirror() { * @return the destructured iso */ default Tuple2, Fn1> unIso() { - return Tuple2.fill(this., Identity, Identity, Identity, + return Tuple2.fill(this., Identity, Identity, Identity, Exchange>, Exchange>>apply(new Exchange<>(id(), Identity::new)).diMapR(Identity::runIdentity)) .biMap(e -> fn1(e.sa()), e -> fn1(e.bt())); @@ -226,8 +226,9 @@ static Iso iso(Function f, return new Iso() { @Override @SuppressWarnings("unchecked") - public

, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { + public

, F extends Functor, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { return (PSFT) pafb.diMap(f, fb -> (FT) fb.fmap(g)); } }; @@ -311,9 +312,14 @@ default Lens.Simple andThen(LensLike.Simple f) { * @param A/B * @return the simple iso */ - @SuppressWarnings("unchecked") static Iso.Simple adapt(Iso iso) { - return iso::apply; + return new Iso.Simple() { + @Override + public

, F extends Functor, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { + return iso.apply(pafb); + } + }; } } } \ No newline at end of file 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 3f832d351..ba74b982a 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/Lens.java @@ -246,7 +246,7 @@ static Lens lens(Function gette return new Lens() { @Override @SuppressWarnings("unchecked") - public , FB extends Functor> FT apply( + public , FT extends Functor, FB extends Functor> FT apply( Function fn, S s) { return (FT) fn.apply(getter.apply(s)).fmap(b -> setter.apply(s, b)); @@ -325,9 +325,14 @@ default Lens.Simple andThen(LensLike.Simple f) { * @param A/B * @return the simple lens */ - @SuppressWarnings("unchecked") static Lens.Simple adapt(Lens lens) { - return lens::apply; + return new Lens.Simple() { + @Override + public , FT extends Functor, FB extends Functor> FT apply( + Function fn, S s) { + return lens.apply(fn, s); + } + }; } /** diff --git a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java b/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java index 5551e172a..4975544ba 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java @@ -20,9 +20,11 @@ * @see Lens * @see Iso */ -public interface LensLike extends Monad>, Profunctor> { +public interface LensLike extends + Monad>, + Profunctor> { - , FB extends Functor> FT apply( + , FT extends Functor, FB extends Functor> FT apply( Function fn, S s); /** diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java b/src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java index 5c1de0104..a0c1eaedd 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java @@ -25,14 +25,16 @@ */ public final class Over implements Fn3, Function, S, T> { - private static final Over INSTANCE = new Over(); + private static final Over INSTANCE = new Over<>(); private Over() { } @Override public T apply(LensLike lens, Function fn, S s) { - return lens., Identity>apply(fn.andThen((Function>) Identity::new), s).runIdentity(); + return lens., Identity, Identity>apply(fn.andThen((Function>) Identity::new), + s) + .runIdentity(); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java b/src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java index 07c97b804..cebf0647f 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java @@ -25,7 +25,7 @@ */ public final class Set implements Fn3, B, S, T> { - private static final Set INSTANCE = new Set(); + private static final Set INSTANCE = new Set<>(); private Set() { } @@ -37,7 +37,7 @@ public T apply(LensLike lens, B b, S s) { @SuppressWarnings("unchecked") public static Set set() { - return INSTANCE; + return (Set) INSTANCE; } public static Fn2 set(LensLike lens) { diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java b/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java index 11c37a1e5..1bdae90bf 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java @@ -23,7 +23,7 @@ */ public final class Under implements Fn3, Function, B, A> { - private static final Under INSTANCE = new Under(); + private static final Under INSTANCE = new Under<>(); private Under() { } @@ -35,7 +35,7 @@ public A apply(Iso iso, Function fn, B b) { @SuppressWarnings("unchecked") public static Under under() { - return INSTANCE; + return (Under) INSTANCE; } public static Fn2, B, A> under(Iso iso) { diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/View.java b/src/main/java/com/jnape/palatable/lambda/lens/functions/View.java index a6d1cb883..b4df1138d 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/View.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/functions/View.java @@ -20,7 +20,7 @@ */ public final class View implements Fn2, S, A> { - private static final View INSTANCE = new View(); + private static final View INSTANCE = new View<>(); private View() { } @@ -32,7 +32,7 @@ public A apply(LensLike lens, S s) { @SuppressWarnings("unchecked") public static View view() { - return INSTANCE; + return (View) INSTANCE; } public static Fn1 view(LensLike lens) { diff --git a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java index e56d0ca39..ef1e26a2b 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java @@ -27,7 +27,7 @@ * @param the type of the parameter * @param the unification parameter to more tightly type-constrain Monads to themselves */ -public interface Monad extends Applicative { +public interface Monad> extends Applicative { /** * Chain dependent computations that may continue or short-circuit based on previous results. @@ -65,7 +65,7 @@ default Monad zip(Applicative, M> app */ @Override default Lazy> lazyZip(Lazy, M>> lazyAppFn) { - return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); } /** @@ -93,7 +93,7 @@ default Monad discardR(Applicative appB) { * @param the nested monad * @return the nested monad */ - static > MA join(Monad mma) { + static , A, MA extends Monad> MA join(Monad mma) { return mma.flatMap(id()).coerce(); } } \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java index 6cce48bfd..5b93eac91 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java @@ -21,7 +21,7 @@ */ public final class AddAll> implements MonoidFactory, C> { - private static final AddAll INSTANCE = new AddAll(); + private static final AddAll INSTANCE = new AddAll<>(); private AddAll() { } @@ -54,7 +54,7 @@ public C foldMap(Function fn, Iterable bs) { @SuppressWarnings("unchecked") public static > AddAll addAll() { - return INSTANCE; + return (AddAll) INSTANCE; } public static > Monoid addAll(Supplier collectionSupplier) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java index 51cf36970..336e3cf6e 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java @@ -23,7 +23,7 @@ */ public final class Collapse<_1, _2> implements BiMonoidFactory, Monoid<_2>, Tuple2<_1, _2>> { - private static final Collapse INSTANCE = new Collapse(); + private static final Collapse INSTANCE = new Collapse<>(); private Collapse() { } @@ -36,7 +36,7 @@ public Monoid> apply(Monoid<_1> _1Monoid, Monoid<_2> _2Monoid) { @SuppressWarnings("unchecked") public static <_1, _2> Collapse<_1, _2> collapse() { - return INSTANCE; + return (Collapse<_1, _2>) INSTANCE; } public static <_1, _2> MonoidFactory, Tuple2<_1, _2>> collapse(Monoid<_1> _1Monoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java index ca27bb28f..6c9945784 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java @@ -24,7 +24,7 @@ */ public final class Compose implements MonoidFactory, CompletableFuture> { - private static final Compose INSTANCE = new Compose(); + private static final Compose INSTANCE = new Compose<>(); private Compose() { } @@ -37,7 +37,7 @@ public Monoid> apply(Monoid aMonoid) { @SuppressWarnings("unchecked") public static Compose compose() { - return INSTANCE; + return (Compose) INSTANCE; } public static Monoid> compose(Monoid aMonoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java index 2d164bbdc..dd1ae290e 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java @@ -17,7 +17,7 @@ */ public final class Concat implements Monoid> { - private static final Concat INSTANCE = new Concat(); + private static final Concat INSTANCE = new Concat<>(); private Concat() { } @@ -39,7 +39,7 @@ public Iterable foldMap(Function> fn, It @SuppressWarnings("unchecked") public static Concat concat() { - return INSTANCE; + return (Concat) INSTANCE; } public static Fn1, Iterable> concat(Iterable xs) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java index cb3b65f4c..9d074aaea 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java @@ -23,7 +23,7 @@ */ public final class First implements Monoid> { - private static final First INSTANCE = new First(); + private static final First INSTANCE = new First<>(); private First() { } @@ -45,7 +45,7 @@ public Maybe foldMap(Function> fn, Iterable @SuppressWarnings("unchecked") public static First first() { - return INSTANCE; + return (First) INSTANCE; } public static Fn1, Maybe> first(Maybe x) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java index bb039c09a..775e6448f 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java @@ -19,7 +19,7 @@ * @see Maybe */ public final class Last implements Monoid> { - private static final Last INSTANCE = new Last(); + private static final Last INSTANCE = new Last<>(); private Last() { } @@ -36,7 +36,7 @@ public Maybe apply(Maybe x, Maybe y) { @SuppressWarnings("unchecked") public static Last last() { - return INSTANCE; + return (Last) INSTANCE; } public static Fn1, Maybe> last(Maybe x) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java index 5026328fb..906a34658 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java @@ -29,7 +29,7 @@ */ public final class LeftAll implements MonoidFactory, Either> { - private static final LeftAll INSTANCE = new LeftAll(); + private static final LeftAll INSTANCE = new LeftAll<>(); private LeftAll() { } @@ -42,7 +42,7 @@ public Monoid> apply(Monoid lMonoid) { @SuppressWarnings("unchecked") public static LeftAll leftAll() { - return INSTANCE; + return (LeftAll) INSTANCE; } public static Monoid> leftAll(Monoid lMonoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java index a9035d67c..9ba5a8cc7 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java @@ -29,7 +29,7 @@ */ public final class LeftAny implements MonoidFactory, Either> { - private static final LeftAny INSTANCE = new LeftAny(); + private static final LeftAny INSTANCE = new LeftAny<>(); private LeftAny() { } @@ -42,7 +42,7 @@ public Monoid> apply(Monoid lMonoid) { @SuppressWarnings("unchecked") public static LeftAny leftAny() { - return INSTANCE; + return (LeftAny) INSTANCE; } public static Monoid> leftAny(Monoid lMonoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java index 798b6041a..5b6f7f8df 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java @@ -22,7 +22,7 @@ */ public final class Merge implements BiMonoidFactory, Monoid, Either> { - private static final Merge INSTANCE = new Merge(); + private static final Merge INSTANCE = new Merge<>(); private Merge() { } @@ -35,7 +35,7 @@ public Monoid> apply(Semigroup lSemigroup, Monoid rMonoid) { @SuppressWarnings("unchecked") public static Merge merge() { - return INSTANCE; + return (Merge) INSTANCE; } public static MonoidFactory, Either> merge(Semigroup lSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java index 104d6f7d5..4e5b54ea2 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java @@ -21,7 +21,7 @@ */ public final class MergeMaps implements BiMonoidFactory>, Semigroup, Map> { - private static final MergeMaps INSTANCE = new MergeMaps(); + private static final MergeMaps INSTANCE = new MergeMaps<>(); private MergeMaps() { } @@ -38,7 +38,7 @@ public Monoid> apply(Supplier> mSupplier, Semigroup semig @SuppressWarnings("unchecked") public static MergeMaps mergeMaps() { - return INSTANCE; + return (MergeMaps) INSTANCE; } public static MonoidFactory, Map> mergeMaps(Supplier> mSupplier) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java index f357d5da4..ff25246c7 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java @@ -29,7 +29,7 @@ */ public final class RightAny implements MonoidFactory, Either> { - private static final RightAny INSTANCE = new RightAny(); + private static final RightAny INSTANCE = new RightAny<>(); private RightAny() { } @@ -42,7 +42,7 @@ public Monoid> apply(Monoid rMonoid) { @SuppressWarnings("unchecked") public static RightAny rightAny() { - return INSTANCE; + return (RightAny) INSTANCE; } public static Monoid> rightAny(Monoid rMonoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java index 871deebb1..b3ab1c93e 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java @@ -17,7 +17,7 @@ */ public final class RunAll implements MonoidFactory, IO> { - private static final RunAll INSTANCE = new RunAll(); + private static final RunAll INSTANCE = new RunAll<>(); private RunAll() { } @@ -30,7 +30,7 @@ public Monoid> apply(Monoid monoid) { @SuppressWarnings("unchecked") public static RunAll runAll() { - return INSTANCE; + return (RunAll) INSTANCE; } public static Monoid> runAll(Monoid monoid) { diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java index d119e0a50..4594f328e 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java @@ -15,7 +15,7 @@ */ public final class Union implements Monoid> { - private static final Union INSTANCE = new Union(); + private static final Union INSTANCE = new Union<>(); private Union() { } @@ -32,7 +32,7 @@ public Iterable apply(Iterable xs, Iterable ys) { @SuppressWarnings("unchecked") public static Union union() { - return INSTANCE; + return (Union) INSTANCE; } public static Fn1, Iterable> union(Iterable xs) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java index 9c5392860..f2991e238 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java @@ -32,7 +32,7 @@ private Absent() { @Override public Semigroup> apply(Semigroup aSemigroup) { - return LiftA2., Maybe, Maybe>liftA2(aSemigroup.toBiFunction())::apply; + return LiftA2., Maybe, Maybe, Maybe>liftA2(aSemigroup.toBiFunction())::apply; } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java index 9c2046632..d1a3b6eca 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java @@ -21,7 +21,7 @@ */ public final class Collapse<_1, _2> implements BiSemigroupFactory, Semigroup<_2>, Tuple2<_1, _2>> { - private static final Collapse INSTANCE = new Collapse(); + private static final Collapse INSTANCE = new Collapse<>(); private Collapse() { } @@ -34,7 +34,7 @@ public Semigroup> apply(Semigroup<_1> _1Semigroup, Semigroup<_2> @SuppressWarnings("unchecked") public static <_1, _2> Collapse<_1, _2> collapse() { - return INSTANCE; + return (Collapse<_1, _2>) INSTANCE; } public static <_1, _2> SemigroupFactory, Tuple2<_1, _2>> collapse(Semigroup<_1> _1Semigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java index 9857ab413..0bb9a2a41 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java @@ -20,7 +20,7 @@ */ public final class Compose implements SemigroupFactory, CompletableFuture> { - private static final Compose INSTANCE = new Compose(); + private static final Compose INSTANCE = new Compose<>(); private Compose() { } @@ -32,7 +32,7 @@ public Semigroup> apply(Semigroup aSemigroup) { @SuppressWarnings("unchecked") public static Compose compose() { - return INSTANCE; + return (Compose) INSTANCE; } public static Semigroup> compose(Semigroup aSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java index b8955b2e0..780c61f89 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java @@ -30,7 +30,7 @@ */ public final class LeftAll implements SemigroupFactory, Either> { - private static final LeftAll INSTANCE = new LeftAll(); + private static final LeftAll INSTANCE = new LeftAll<>(); private LeftAll() { } @@ -42,7 +42,7 @@ public Semigroup> apply(Semigroup lSemigroup) { @SuppressWarnings("unchecked") public static LeftAll leftAll() { - return INSTANCE; + return (LeftAll) INSTANCE; } public static Semigroup> leftAll(Semigroup lSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java index b93133143..233246b89 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java @@ -29,7 +29,7 @@ */ public final class LeftAny implements SemigroupFactory, Either> { - private static final LeftAny INSTANCE = new LeftAny(); + private static final LeftAny INSTANCE = new LeftAny<>(); private LeftAny() { } @@ -43,7 +43,7 @@ public Semigroup> apply(Semigroup lSemigroup) { @SuppressWarnings("unchecked") public static LeftAny leftAny() { - return INSTANCE; + return (LeftAny) INSTANCE; } public static Semigroup> leftAny(Semigroup lSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java index 3687a5187..001a39a3e 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java @@ -20,7 +20,7 @@ */ public final class Max> implements Semigroup { - private static final Max INSTANCE = new Max(); + private static final Max INSTANCE = new Max<>(); private Max() { } @@ -32,7 +32,7 @@ public A apply(A x, A y) { @SuppressWarnings("unchecked") public static > Max max() { - return INSTANCE; + return (Max) INSTANCE; } public static > Fn1 max(A x) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java index 5e6cbbe5c..d00bcbb4b 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java @@ -24,7 +24,7 @@ */ public final class MaxBy> implements SemigroupFactory, A> { - private static final MaxBy INSTANCE = new MaxBy(); + private static final MaxBy INSTANCE = new MaxBy<>(); private MaxBy() { } @@ -36,7 +36,7 @@ public Semigroup apply(Function compareFn) { @SuppressWarnings("unchecked") public static > MaxBy maxBy() { - return INSTANCE; + return (MaxBy) INSTANCE; } public static > Semigroup maxBy( diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java index 75bd81ffd..eaf5e355b 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java @@ -20,7 +20,7 @@ */ public final class Merge implements BiSemigroupFactory, Semigroup, Either> { - private static final Merge INSTANCE = new Merge(); + private static final Merge INSTANCE = new Merge<>(); private Merge() { } @@ -32,7 +32,7 @@ public Semigroup> apply(Semigroup lSemigroup, Semigroup rSemi @SuppressWarnings("unchecked") public static Merge merge() { - return INSTANCE; + return (Merge) INSTANCE; } public static SemigroupFactory, Either> merge(Semigroup lSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java index 742055ed5..f700e4612 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java @@ -20,7 +20,7 @@ */ public final class Min> implements Semigroup { - private static final Min INSTANCE = new Min(); + private static final Min INSTANCE = new Min<>(); private Min() { } @@ -32,7 +32,7 @@ public A apply(A x, A y) { @SuppressWarnings("unchecked") public static > Min min() { - return INSTANCE; + return (Min) INSTANCE; } public static > Fn1 min(A x) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java index 3a7ea9a71..4458a55bc 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java @@ -24,7 +24,7 @@ */ public final class MinBy> implements SemigroupFactory, A> { - private static final MinBy INSTANCE = new MinBy(); + private static final MinBy INSTANCE = new MinBy<>(); private MinBy() { } @@ -36,7 +36,7 @@ public Semigroup apply(Function compareFn) { @SuppressWarnings("unchecked") public static > MinBy minBy() { - return INSTANCE; + return (MinBy) INSTANCE; } public static > Semigroup minBy( diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java index 7f1bdab5b..8c69fbd94 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java @@ -29,7 +29,7 @@ */ public final class RightAll implements SemigroupFactory, Either> { - private static final RightAll INSTANCE = new RightAll(); + private static final RightAll INSTANCE = new RightAll<>(); private RightAll() { } @@ -41,7 +41,7 @@ public Semigroup> apply(Semigroup rSemigroup) { @SuppressWarnings("unchecked") public static RightAll rightAll() { - return INSTANCE; + return (RightAll) INSTANCE; } public static Semigroup> rightAll(Semigroup rSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java index 00f528054..7d2f1d864 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java @@ -30,7 +30,7 @@ */ public final class RightAny implements SemigroupFactory, Either> { - private static final RightAny INSTANCE = new RightAny(); + private static final RightAny INSTANCE = new RightAny<>(); private RightAny() { } @@ -44,7 +44,7 @@ public Semigroup> apply(Semigroup rSemigroup) { @SuppressWarnings("unchecked") public static RightAny rightAny() { - return INSTANCE; + return (RightAny) INSTANCE; } public static Semigroup> rightAny(Semigroup rSemigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java index b46ff9612..34a2eeb2b 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java @@ -13,7 +13,7 @@ */ public final class RunAll implements SemigroupFactory, IO> { - private static final RunAll INSTANCE = new RunAll(); + private static final RunAll INSTANCE = new RunAll<>(); private RunAll() { } @@ -25,7 +25,7 @@ public Semigroup> apply(Semigroup semigroup) { @SuppressWarnings("unchecked") public static RunAll runAll() { - return INSTANCE; + return (RunAll) INSTANCE; } public static Semigroup> runAll(Semigroup semigroup) { 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 0dfb2b7e3..81928dc81 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -23,7 +23,7 @@ * @param the {@link Iterable} element type * @see LambdaMap */ -public final class LambdaIterable implements Monad, Traversable { +public final class LambdaIterable implements Monad>, Traversable> { private final Iterable as; @SuppressWarnings("unchecked") @@ -67,7 +67,7 @@ public LambdaIterable pure(B b) { * @return the zipped LambdaIterable */ @Override - public LambdaIterable zip(Applicative, LambdaIterable> appFn) { + public LambdaIterable zip(Applicative, LambdaIterable> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -76,7 +76,7 @@ public LambdaIterable zip(Applicative, L */ @Override public Lazy> lazyZip( - Lazy, LambdaIterable>> lazyAppFn) { + Lazy, LambdaIterable>> lazyAppFn) { return Empty.empty(as) ? lazy(LambdaIterable.empty()) : Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); @@ -86,7 +86,7 @@ public Lazy> lazyZip( * {@inheritDoc} */ @Override - public LambdaIterable discardL(Applicative appB) { + public LambdaIterable discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } @@ -94,7 +94,7 @@ public LambdaIterable discardL(Applicative appB) { * {@inheritDoc} */ @Override - public LambdaIterable discardR(Applicative appB) { + public LambdaIterable discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } @@ -102,7 +102,7 @@ public LambdaIterable discardR(Applicative appB) { * {@inheritDoc} */ @Override - public LambdaIterable flatMap(Function> f) { + public LambdaIterable flatMap(Function>> f) { return wrap(flatten(map(a -> f.apply(a).>coerce().unwrap(), as))); } @@ -111,7 +111,8 @@ public LambdaIterable flatMap(Function, AppB extends Applicative, + public , TravB extends Traversable>, + AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse(Function fn, Function pure) { return FoldRight.foldRight( diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java index 20205a419..5b683de69 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java @@ -46,12 +46,15 @@ public LambdaMap fmap(Function fn) { @Override @SuppressWarnings("unchecked") - public >, AppC extends Applicative, AppTrav extends Applicative> AppTrav traverse( - Function fn, Function pure) { - return foldLeft(Fn2., AppTrav>fn2(appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> { - ((LambdaMap) m).unwrap().put(k, v); - return (TravC) m; - })))).toBiFunction(), + public , TravC extends Traversable>, + AppC extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { + return foldLeft(Fn2., AppTrav>fn2( + appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> { + ((LambdaMap) m).unwrap().put(k, v); + return (TravC) m; + })))).toBiFunction(), pure.apply((TravC) LambdaMap.wrap(new HashMap<>())), this.fmap(fn).unwrap().entrySet()); } diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java index aff6884da..ec52e4e51 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java @@ -30,7 +30,7 @@ * @param The type of the parameter * @param The unification parameter */ -public interface Traversable extends Functor { +public interface Traversable> extends Functor { /** * Apply fn to each element of this traversable from left to right, and collapse the results into @@ -45,7 +45,7 @@ public interface Traversable extends Functor { * @param the full inferred resulting type from the traversal * @return the traversed Traversable, wrapped inside an applicative */ - , AppB extends Applicative, + , TravB extends Traversable, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse( Function fn, Function pure); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/KleisliTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/KleisliTest.java index bd40b2dca..8be6844fe 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/KleisliTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/KleisliTest.java @@ -9,8 +9,8 @@ public class KleisliTest { - private static final Kleisli> G = kleisli(i -> new Identity<>(i.toString())); - private static final Kleisli> F = kleisli(s -> new Identity<>(parseInt(s))); + private static final Kleisli, Identity> G = kleisli(i -> new Identity<>(i.toString())); + private static final Kleisli, Identity> F = kleisli(s -> new Identity<>(parseInt(s))); @Test public void leftToRightComposition() { diff --git a/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java b/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java index ce89ba26e..4cb93cf08 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java @@ -15,7 +15,8 @@ public class BifunctorTest { @Test public void biMapLUsesIdentityForRightBiMapFunction() { AtomicReference rightInvocation = new AtomicReference<>(); - Bifunctor bifunctor = new InvocationRecordingBifunctor<>(new AtomicReference<>(), rightInvocation); + Bifunctor> bifunctor = + new InvocationRecordingBifunctor<>(new AtomicReference<>(), rightInvocation); bifunctor.biMapL(String::toUpperCase); assertThat(rightInvocation.get(), is(id())); } @@ -23,7 +24,8 @@ public void biMapLUsesIdentityForRightBiMapFunction() { @Test public void biMapRUsesIdentityForLeftBiMapFunction() { AtomicReference leftInvocation = new AtomicReference<>(); - Bifunctor bifunctor = new InvocationRecordingBifunctor<>(leftInvocation, new AtomicReference<>()); + Bifunctor> bifunctor = + new InvocationRecordingBifunctor<>(leftInvocation, new AtomicReference<>()); bifunctor.biMapR(String::valueOf); assertThat(leftInvocation.get(), is(id())); } diff --git a/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java b/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java index 0f7358250..f2fb6980d 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java @@ -15,7 +15,8 @@ public class ProfunctorTest { @Test public void diMapLUsesIdentityForRightDiMapFunction() { AtomicReference rightInvocation = new AtomicReference<>(); - Profunctor profunctor = new InvocationRecordingProfunctor<>(new AtomicReference<>(), rightInvocation); + Profunctor> profunctor = + new InvocationRecordingProfunctor<>(new AtomicReference<>(), rightInvocation); profunctor.diMapL(Object::toString); assertThat(rightInvocation.get(), is(id())); } @@ -23,7 +24,8 @@ public void diMapLUsesIdentityForRightDiMapFunction() { @Test public void diMapRUsesIdentityForLeftDiMapFunction() { AtomicReference leftInvocation = new AtomicReference<>(); - Profunctor profunctor = new InvocationRecordingProfunctor<>(leftInvocation, new AtomicReference<>()); + Profunctor> profunctor = + new InvocationRecordingProfunctor<>(leftInvocation, new AtomicReference<>()); profunctor.diMapR(String::valueOf); assertThat(leftInvocation.get(), is(id())); } diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java index 3cc6198fc..66303c375 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java @@ -17,7 +17,7 @@ public class ComposeTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class}) - public Compose testSubject() { + public Compose, Identity, Integer> testSubject() { return new Compose<>(new Identity<>(new Identity<>(1))); } 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 f5478be8f..7d609e980 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java @@ -47,7 +47,7 @@ public class LensTest { @Test public void setsUnderIdentity() { - Set ints = LENS.>, Identity>apply(s -> new Identity<>(s.length()), asList("foo", "bar", "baz")).runIdentity(); + Set ints = LENS., Identity>, Identity>apply(s -> new Identity<>(s.length()), asList("foo", "bar", "baz")).runIdentity(); assertEquals(singleton(3), ints); } @@ -67,7 +67,7 @@ public void mapsIndividuallyOverParameters() { .mapB((Maybe maybeI) -> maybeI.orElse(-1)); assertEquals(just(true), - theGambit.>, Identity>>apply( + theGambit., Identity>, Identity>>apply( maybeC -> new Identity<>(maybeC.fmap(c -> parseInt(Character.toString(c)))), just("321")).runIdentity() ); diff --git a/src/test/java/testsupport/EquatableM.java b/src/test/java/testsupport/EquatableM.java index 2478e5a97..72feb443d 100644 --- a/src/test/java/testsupport/EquatableM.java +++ b/src/test/java/testsupport/EquatableM.java @@ -6,7 +6,7 @@ import java.util.Objects; import java.util.function.Function; -public final class EquatableM, A> implements Monad> { +public final class EquatableM, A> implements Monad> { private final Monad ma; private final Function equatable; diff --git a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java index e1ab75465..92565e2de 100644 --- a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java +++ b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java @@ -5,7 +5,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; -public final class InvocationRecordingBifunctor implements Bifunctor { +public final class InvocationRecordingBifunctor implements Bifunctor> { private final AtomicReference leftFn; private final AtomicReference rightFn; diff --git a/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java b/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java index 4f440bb38..ac9e53fba 100644 --- a/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java +++ b/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java @@ -5,7 +5,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; -public final class InvocationRecordingProfunctor implements Profunctor { +public final class InvocationRecordingProfunctor implements Profunctor> { private final AtomicReference leftFn; private final AtomicReference rightFn; diff --git a/src/test/java/testsupport/traits/ApplicativeLaws.java b/src/test/java/testsupport/traits/ApplicativeLaws.java index 42fd8bbde..11397da5a 100644 --- a/src/test/java/testsupport/traits/ApplicativeLaws.java +++ b/src/test/java/testsupport/traits/ApplicativeLaws.java @@ -16,7 +16,7 @@ import static java.util.Arrays.asList; import static java.util.function.Function.identity; -public class ApplicativeLaws implements Trait> { +public class ApplicativeLaws> implements Trait> { @Override public void test(Applicative applicative) { diff --git a/src/test/java/testsupport/traits/BifunctorLaws.java b/src/test/java/testsupport/traits/BifunctorLaws.java index b8bb42856..55278590e 100644 --- a/src/test/java/testsupport/traits/BifunctorLaws.java +++ b/src/test/java/testsupport/traits/BifunctorLaws.java @@ -12,7 +12,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static java.util.Arrays.asList; -public class BifunctorLaws implements Trait> { +public class BifunctorLaws> implements Trait> { @Override public void test(Bifunctor bifunctor) { @@ -30,19 +30,19 @@ public void test(Bifunctor bifunctor) { private Maybe testLeftIdentity(Bifunctor bifunctor) { return bifunctor.biMapL(id()).equals(bifunctor) - ? nothing() - : just("left identity (bifunctor.biMapL(id()).equals(bifunctor))"); + ? nothing() + : just("left identity (bifunctor.biMapL(id()).equals(bifunctor))"); } private Maybe testRightIdentity(Bifunctor bifunctor) { return bifunctor.biMapR(id()).equals(bifunctor) - ? nothing() - : just("right identity (bifunctor.biMapR(id()).equals(bifunctor))"); + ? nothing() + : just("right identity (bifunctor.biMapR(id()).equals(bifunctor))"); } private Maybe testMutualIdentity(Bifunctor bifunctor) { return bifunctor.biMapL(id()).biMapR(id()).equals(bifunctor.biMap(id(), id())) - ? nothing() - : just("mutual identity (bifunctor.biMapL(id()).biMapR(id()).equals(bifunctor.biMap(id(),id()))"); + ? nothing() + : just("mutual identity (bifunctor.biMapL(id()).biMapR(id()).equals(bifunctor.biMap(id(),id()))"); } } diff --git a/src/test/java/testsupport/traits/FunctorLaws.java b/src/test/java/testsupport/traits/FunctorLaws.java index a6b5f3d0e..dbe96c6e5 100644 --- a/src/test/java/testsupport/traits/FunctorLaws.java +++ b/src/test/java/testsupport/traits/FunctorLaws.java @@ -13,7 +13,7 @@ import static java.util.Arrays.asList; import static java.util.function.Function.identity; -public class FunctorLaws implements Trait> { +public class FunctorLaws> implements Trait> { @Override public void test(Functor f) { @@ -29,8 +29,8 @@ public void test(Functor f) { private Maybe testIdentity(Functor f) { return f.fmap(identity()).equals(f) - ? nothing() - : just("identity (f.fmap(identity()).equals(f))"); + ? nothing() + : just("identity (f.fmap(identity()).equals(f))"); } private Maybe testComposition(Functor functor) { @@ -38,7 +38,7 @@ private Maybe testComposition(Functor functor) { Function f = x -> x * 3; Function g = x -> x - 2; return subject.fmap(f.compose(g)).equals(subject.fmap(g).fmap(f)) - ? nothing() - : just("composition (functor.fmap(f.compose(g)).equals(functor.fmap(g).fmap(f)))"); + ? nothing() + : just("composition (functor.fmap(f.compose(g)).equals(functor.fmap(g).fmap(f)))"); } } diff --git a/src/test/java/testsupport/traits/MonadLaws.java b/src/test/java/testsupport/traits/MonadLaws.java index 038fc6789..98738eb57 100644 --- a/src/test/java/testsupport/traits/MonadLaws.java +++ b/src/test/java/testsupport/traits/MonadLaws.java @@ -16,7 +16,7 @@ import static com.jnape.palatable.lambda.monad.Monad.join; import static java.util.Arrays.asList; -public class MonadLaws implements Trait> { +public class MonadLaws> implements Trait> { @Override public void test(Monad m) { diff --git a/src/test/java/testsupport/traits/TraversableLaws.java b/src/test/java/testsupport/traits/TraversableLaws.java index 8ce0ab0f0..a9095fd97 100644 --- a/src/test/java/testsupport/traits/TraversableLaws.java +++ b/src/test/java/testsupport/traits/TraversableLaws.java @@ -18,7 +18,7 @@ import static java.util.Arrays.asList; @SuppressWarnings("Convert2MethodRef") -public class TraversableLaws implements Trait> { +public class TraversableLaws> implements Trait> { @Override public void test(Traversable traversable) { @@ -38,31 +38,30 @@ private Maybe testNaturality(Traversable trav) { Function> f = Identity::new; Function, Either> t = id -> right(id.runIdentity()); - Function, Applicative, Identity>> pureFn = x -> new Identity<>(x); + Function, Applicative, Identity>> pureFn = x -> new Identity<>(x); Function, Applicative, Either>> pureFn2 = x -> right(x); return t.apply(trav.traverse(f, pureFn).fmap(id()).coerce()) - .equals(trav.traverse(t.compose(f), pureFn2).fmap(id()).coerce()) - ? nothing() - : just("naturality (t.apply(trav.traverse(f, pureFn).fmap(id()).coerce())\n" + - " .equals(trav.traverse(t.compose(f), pureFn2).fmap(id()).coerce()))"); + .equals(trav.traverse(t.compose(f), pureFn2).fmap(id()).coerce()) + ? nothing() + : just("naturality (t.apply(trav.traverse(f, pureFn).fmap(id()).coerce())\n" + + " .equals(trav.traverse(t.compose(f), pureFn2).fmap(id()).coerce()))"); } private Maybe testIdentity(Traversable trav) { return trav.traverse(Identity::new, x -> new Identity<>(x)).equals(new Identity<>(trav)) - ? nothing() - : just("identity (trav.traverse(Identity::new, x -> new Identity<>(x)).equals(new Identity<>(trav))"); + ? nothing() + : just("identity (trav.traverse(Identity::new, x -> new Identity<>(x)).equals(new Identity<>(trav))"); } - @SuppressWarnings("unchecked") private Maybe testComposition(Traversable trav) { Function> f = Identity::new; - Function> g = x -> new Identity<>(x); + Function>> g = x -> new Identity<>(x); return trav.traverse(f.andThen(x -> x.fmap(g)).andThen(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x)))) .equals(new Compose<>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x))))) - ? nothing() - : just("compose (trav.traverse(f.andThen(x -> x.fmap(g)).andThen(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x))))\n" + - " .equals(new Compose>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x))))))"); + ? nothing() + : just("compose (trav.traverse(f.andThen(x -> x.fmap(g)).andThen(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x))))\n" + + " .equals(new Compose>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x))))))"); } } From f7c3008b94710b51cc7717a13e9886499882a531 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 14 Apr 2019 17:02:07 -0500 Subject: [PATCH 118/348] More elimination of warnings --- .../jnape/palatable/lambda/adt/Either.java | 3 +- .../com/jnape/palatable/lambda/adt/Maybe.java | 5 +-- .../com/jnape/palatable/lambda/adt/These.java | 5 +-- .../com/jnape/palatable/lambda/adt/Try.java | 4 ++- .../palatable/lambda/adt/choice/Choice2.java | 3 +- .../palatable/lambda/adt/choice/Choice3.java | 3 +- .../palatable/lambda/adt/choice/Choice4.java | 3 +- .../palatable/lambda/adt/choice/Choice5.java | 3 +- .../palatable/lambda/adt/choice/Choice6.java | 3 +- .../palatable/lambda/adt/choice/Choice7.java | 3 +- .../palatable/lambda/adt/choice/Choice8.java | 3 +- .../lambda/adt/hlist/SingletonHList.java | 4 +-- .../palatable/lambda/adt/hlist/Tuple2.java | 2 +- .../palatable/lambda/adt/hlist/Tuple3.java | 4 +-- .../palatable/lambda/adt/hlist/Tuple4.java | 4 +-- .../palatable/lambda/adt/hlist/Tuple5.java | 4 +-- .../palatable/lambda/adt/hlist/Tuple6.java | 4 +-- .../palatable/lambda/adt/hlist/Tuple7.java | 4 +-- .../palatable/lambda/adt/hlist/Tuple8.java | 5 +-- .../jnape/palatable/lambda/adt/hmap/HMap.java | 20 +++++------ .../palatable/lambda/adt/hmap/Schema.java | 36 +++++++++++++------ .../lambda/adt/hmap/TypeSafeKey.java | 7 +++- .../jnape/palatable/lambda/functions/Fn1.java | 4 ++- .../lambda/functions/builtin/fn1/Cycle.java | 1 + .../lambda/functions/builtin/fn1/Upcast.java | 4 +-- .../lambda/functions/specialized/Kleisli.java | 2 ++ .../palatable/lambda/functor/Applicative.java | 4 +-- .../lambda/functor/builtin/Compose.java | 12 ++++--- .../lambda/functor/builtin/Const.java | 7 ++-- .../lambda/functor/builtin/Identity.java | 7 ++-- .../com/jnape/palatable/lambda/io/IO.java | 6 ++-- .../IterationInterruptedException.java | 1 + .../com/jnape/palatable/lambda/lens/Iso.java | 22 +++++++----- .../com/jnape/palatable/lambda/lens/Lens.java | 14 ++++---- .../jnape/palatable/lambda/lens/LensLike.java | 4 +-- .../lambda/lens/lenses/CollectionLens.java | 3 +- .../jnape/palatable/lambda/monad/Monad.java | 4 ++- .../lambda/monoid/builtin/Present.java | 4 +-- .../lambda/semigroup/builtin/Absent.java | 4 +-- .../lambda/traversable/LambdaIterable.java | 8 +++-- .../lambda/traversable/LambdaMap.java | 2 +- .../lambda/adt/hlist/SingletonHListTest.java | 2 +- .../lambda/adt/hlist/Tuple2Test.java | 3 +- .../lambda/adt/hlist/Tuple3Test.java | 2 +- .../lambda/adt/hlist/Tuple4Test.java | 2 +- .../lambda/adt/hlist/Tuple5Test.java | 2 +- .../lambda/adt/hlist/Tuple6Test.java | 2 +- .../lambda/adt/hlist/Tuple7Test.java | 2 +- .../lambda/adt/hlist/Tuple8Test.java | 2 +- .../palatable/lambda/adt/hmap/HMapTest.java | 4 +-- .../functions/builtin/fn1/CycleTest.java | 2 +- .../functions/builtin/fn1/DistinctTest.java | 2 +- .../functions/builtin/fn1/InitTest.java | 2 +- .../functions/builtin/fn1/InitsTest.java | 2 +- .../builtin/fn1/OccurrencesTest.java | 5 +-- .../functions/builtin/fn1/RepeatTest.java | 2 +- .../functions/builtin/fn1/ReverseTest.java | 2 +- .../functions/builtin/fn1/SizeTest.java | 1 + .../functions/builtin/fn1/TailTest.java | 2 +- .../functions/builtin/fn1/TailsTest.java | 2 +- .../functions/builtin/fn1/UnconsTest.java | 2 +- .../functions/builtin/fn2/FilterTest.java | 2 +- .../functions/builtin/fn2/GroupByTest.java | 4 ++- .../functions/builtin/fn2/IterateTest.java | 2 +- .../lambda/functions/builtin/fn2/MapTest.java | 2 +- .../functions/builtin/fn2/PartitionTest.java | 2 +- .../functions/builtin/fn2/ToMapTest.java | 1 + .../functions/builtin/fn2/UnfoldrTest.java | 2 +- .../lambda/functor/builtin/ConstTest.java | 2 +- .../lambda/functor/builtin/IdentityTest.java | 2 +- .../jnape/palatable/lambda/lens/IsoTest.java | 9 +++-- .../jnape/palatable/lambda/lens/LensTest.java | 2 +- .../lambda/lens/lenses/MapLensTest.java | 1 + .../lambda/monoid/builtin/AddAllTest.java | 1 + .../lambda/traversable/LambdaMapTest.java | 1 + src/test/java/testsupport/EquatableM.java | 5 +++ .../traits/EmptyIterableSupport.java | 6 ++-- .../testsupport/traits/FiniteIteration.java | 6 ++-- .../traits/ImmutableIteration.java | 6 ++-- .../traits/InfiniteIterableSupport.java | 4 +-- .../testsupport/traits/InfiniteIteration.java | 6 ++-- .../java/testsupport/traits/Laziness.java | 6 ++-- 82 files changed, 223 insertions(+), 139 deletions(-) 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 cea6eac17..85b538c47 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -256,10 +256,11 @@ public final Either zip(Applicative Lazy> lazyZip( - Lazy, Either>> lazyAppFn) { + Lazy, Either>> lazyAppFn) { return match(l -> lazy(left(l)), r -> lazyAppFn.fmap(eitherLF -> eitherLF.fmap(f -> f.apply(r)).coerce())); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index aeaf59d3c..67c1fd886 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -141,12 +141,13 @@ public final Maybe zip(Applicative, Mayb /** * Terminate early if this is a {@link Nothing}; otherwise, continue the {@link Applicative#zip zip}. * - * @param lazyAppFn the lazy other applicative instance * @param the result type + * @param lazyAppFn the lazy other applicative instance * @return the zipped {@link Maybe} */ @Override - public Lazy> lazyZip(Lazy, Maybe>> lazyAppFn) { + public Lazy> lazyZip( + Lazy, Maybe>> lazyAppFn) { return match(constantly(lazy(nothing())), a -> lazyAppFn.fmap(maybeF -> maybeF.fmap(f -> f.apply(a)).coerce())); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index e25d0e741..4416135de 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -101,9 +101,10 @@ public final These zip(Applicative, T } @Override - public Lazy> lazyZip(Lazy, These>> lazyAppFn) { + public Lazy> lazyZip( + Lazy, These>> lazyAppFn) { return projectA().>>fmap(a -> lazy(a(a))) - .orElseGet(() -> Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce)); + .orElseGet(() -> Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce)); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index 63b915122..e714739ed 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -174,7 +174,8 @@ public Try zip(Applicative, Try } @Override - public Lazy> lazyZip(Lazy, Try>> lazyAppFn) { + public Lazy> lazyZip( + Lazy, Try>> lazyAppFn) { return match(f -> lazy(failure(f)), s -> lazyAppFn.fmap(tryF -> tryF.fmap(f -> f.apply(s)).coerce())); } @@ -315,6 +316,7 @@ public static Try trying(CheckedRunnable runna * @param the function return type * @return a {@link Try} representing the result of the function's application to the resource */ + @SuppressWarnings("try") public static Try withResources( CheckedSupplier aSupplier, CheckedFn1> fn) { diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index 52eeb2455..b63ed4745 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -114,10 +114,11 @@ public Choice2 zip(Applicative, Choic /** * {@inheritDoc} + * @param lazyAppFn */ @Override public Lazy>> lazyZip( - Lazy, Choice2>> lazyAppFn) { + Lazy, Choice2>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(b)).coerce())); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 7ea524505..c3d8d2697 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -114,10 +114,11 @@ public Choice3 zip(Applicative, Ch /** * {@inheritDoc} + * @param lazyAppFn */ @Override public Lazy> lazyZip( - Lazy, Choice3>> lazyAppFn) { + Lazy, Choice3>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(c)).coerce())); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index be222cbac..a707afc69 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -115,10 +115,11 @@ public Choice4 zip(Applicative, /** * {@inheritDoc} + * @param lazyAppFn */ @Override public Lazy> lazyZip( - Lazy, Choice4>> lazyAppFn) { + Lazy, Choice4>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index a4c12d21d..ed4b4a5b6 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -120,10 +120,11 @@ public Choice5 zip(Applicative Lazy> lazyZip( - Lazy, Choice5>> lazyAppFn) { + Lazy, Choice5>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index 86e2648f5..e3ab3d48f 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -123,10 +123,11 @@ public Choice6 zip( /** * {@inheritDoc} + * @param lazyAppFn */ @Override public Lazy> lazyZip( - Lazy, Choice6>> lazyAppFn) { + Lazy, Choice6>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index 40c678f87..1348293a5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -126,10 +126,11 @@ public Choice7 zip( /** * {@inheritDoc} + * @param lazyAppFn */ @Override public Lazy> lazyZip( - Lazy, Choice7>> lazyAppFn) { + Lazy, Choice7>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index e8fb9debe..b0a70c530 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -119,10 +119,11 @@ public Choice8 zip( /** * {@inheritDoc} + * @param lazyAppFn */ @Override public Lazy> lazyZip( - Lazy, Choice8>> lazyAppFn) { + Lazy, Choice8>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index 8a5be88b9..44bff3484 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -50,8 +50,8 @@ public <_1Prime> SingletonHList<_1Prime> zip( @Override public <_1Prime> Lazy> lazyZip( - Lazy, SingletonHList>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + Lazy, SingletonHList>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_1Prime, SingletonHList>::coerce); } @Override 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 06dc1a20a..9f952849b 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 @@ -112,7 +112,7 @@ public <_2Prime> Tuple2<_1, _2Prime> zip( @Override public <_2Prime> Lazy> lazyZip( - Lazy, Tuple2<_1, ?>>> lazyAppFn) { + Lazy, Tuple2<_1, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_2Prime, Tuple2<_1, ?>>::coerce); } 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 a4601ce19..dd57f1771 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 @@ -114,8 +114,8 @@ public <_3Prime> Tuple3<_1, _2, _3Prime> zip( @Override public <_3Prime> Lazy> lazyZip( - Lazy, Tuple3<_1, _2, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + Lazy, Tuple3<_1, _2, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_3Prime, Tuple3<_1, _2, ?>>::coerce); } @Override 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 6b3c410a5..7ffeb72c5 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 @@ -129,8 +129,8 @@ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> zip( @Override public <_4Prime> Lazy> lazyZip( - Lazy, Tuple4<_1, _2, _3, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + Lazy, Tuple4<_1, _2, _3, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_4Prime, Tuple4<_1, _2, _3, ?>>::coerce); } @Override 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 fe2961fd5..7e6eeb24f 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 @@ -149,8 +149,8 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> zip( @Override public <_5Prime> Lazy> lazyZip( - Lazy, Tuple5<_1, _2, _3, _4, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + Lazy, Tuple5<_1, _2, _3, _4, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_5Prime, Tuple5<_1, _2, _3, _4, ?>>::coerce); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 2231c6a63..464a5abcd 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -169,8 +169,8 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> zip( @Override public <_6Prime> Lazy> lazyZip( - Lazy, Tuple6<_1, _2, _3, _4, _5, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + Lazy, Tuple6<_1, _2, _3, _4, _5, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>::coerce); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index 36e39bca8..bd0c6bbf4 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -188,8 +188,8 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> zip( @Override public <_7Prime> Lazy> lazyZip( - Lazy, Tuple7<_1, _2, _3, _4, _5, _6, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + Lazy, Tuple7<_1, _2, _3, _4, _5, _6, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>::coerce); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index bbc2123cd..b30e68a76 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -207,8 +207,9 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> zip( @Override public <_8Prime> Lazy> lazyZip( - Lazy, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + Lazy, + Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>::coerce); } @Override 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 df5cf50d7..19a166bc1 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 @@ -27,13 +27,13 @@ * @see TypeSafeKey * @see com.jnape.palatable.lambda.adt.hlist.HList */ -public final class HMap implements Iterable> { +public final class HMap implements Iterable, Object>> { private static final HMap EMPTY = new HMap(emptyMap()); - private final Map table; + private final Map, Object> table; - private HMap(Map table) { + private HMap(Map, Object> table) { this.table = table; } @@ -90,7 +90,7 @@ public HMap putAll(HMap hMap) { * @param key the key * @return true if the key is mapped; false otherwise */ - public boolean containsKey(TypeSafeKey key) { + public boolean containsKey(TypeSafeKey key) { return table.containsKey(key); } @@ -100,7 +100,7 @@ public boolean containsKey(TypeSafeKey key) { * @param key the key * @return the updated HMap */ - public HMap remove(TypeSafeKey key) { + public HMap remove(TypeSafeKey key) { return alter(t -> t.remove(key)); } @@ -122,7 +122,7 @@ public HMap removeAll(HMap hMap) { * * @return a {@link Set} of all the mapped keys */ - public Set keys() { + public Set> keys() { return new HashSet<>(table.keySet()); } @@ -141,12 +141,12 @@ public Collection values() { * * @return the map view */ - public Map toMap() { + public Map, Object> toMap() { return new HashMap<>(table); } @Override - public Iterator> iterator() { + public Iterator, Object>> iterator() { return map(Tuple2::fromEntry, table.entrySet()).iterator(); } @@ -171,8 +171,8 @@ public String toString() { '}'; } - private HMap alter(Consumer> alterFn) { - HashMap copy = new HashMap<>(table); + private HMap alter(Consumer, Object>> alterFn) { + HashMap, Object> copy = new HashMap<>(table); alterFn.accept(copy); return new HMap(copy); } 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 index a7e3eb371..6a57cbbbd 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java @@ -12,8 +12,11 @@ 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.functor.Functor; import com.jnape.palatable.lambda.lens.Lens; +import java.util.function.Function; + import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.lens.lenses.HMapLens.valueAt; @@ -27,21 +30,34 @@ */ public interface Schema> extends Lens.Simple> { - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) 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; + Lens, Maybe> lens = 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))); + return new Schema() { + @Override + public , FT extends Functor, FB extends Functor, F>> + FT apply(Function, ? extends FB> fn, HMap hmap) { + return lens.apply(fn, hmap); + } + }; } - @SuppressWarnings("unchecked") static Schema> schema(TypeSafeKey key) { - return valueAt(key) + Lens>, Maybe>> lens = valueAt(key) .mapA(ma -> ma.fmap(HList::singletonHList)) - .>>mapB(maybeSingletonA -> maybeSingletonA.fmap(HCons::head)) - ::apply; + .mapB(maybeSingletonA -> maybeSingletonA.fmap(HCons::head)); + return new Schema>() { + @Override + public , FT extends Functor, + FB extends Functor>, F>> FT apply( + Function>, ? extends FB> fn, HMap hmap) { + return lens.apply(fn, hmap); + } + }; } static Schema> schema(TypeSafeKey aKey, diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java index e07936a2f..2ee0c6622 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java @@ -24,7 +24,7 @@ public interface TypeSafeKey extends Iso.Simple { @Override - default TypeSafeKey discardR(Applicative> appB) { + default TypeSafeKey discardR(Applicative>> appB) { Iso.Simple discarded = Iso.Simple.super.discardR(appB); return new TypeSafeKey() { @Override @@ -95,6 +95,11 @@ static Simple typeSafeKey() { public boolean equals(Object obj) { return obj instanceof Simple ? this == obj : Objects.equals(obj, this); } + + @Override + public int hashCode() { + return super.hashCode(); + } }; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 9bff01745..6384641a8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -97,9 +97,11 @@ default Fn1 zip(Fn2 appFn) { /** * {@inheritDoc} + * @param lazyAppFn */ @Override - default Lazy> lazyZip(Lazy, Fn1>> lazyAppFn) { + default Lazy> lazyZip( + Lazy, Fn1>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java index 10fd2039b..df61e9fa0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java @@ -33,6 +33,7 @@ public static Iterable cycle(Iterable as) { } @SafeVarargs + @SuppressWarnings("varargs") public static Iterable cycle(A... as) { return cycle(asList(as)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java index 08f6fe519..89cfaa864 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java @@ -22,7 +22,7 @@ */ public final class Upcast implements Fn1 { - private static final Upcast INSTANCE = new Upcast<>(); + private static final Upcast INSTANCE = new Upcast<>(); private Upcast() { } @@ -34,7 +34,7 @@ public B apply(A a) { @SuppressWarnings("unchecked") public static Upcast upcast() { - return INSTANCE; + return (Upcast) INSTANCE; } public static B upcast(A a) { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java index 9157c8e44..4fae5b021 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java @@ -25,6 +25,7 @@ public interface Kleisli, MB extends Monad> ex * @param the {@link Monad} instance to return * @return the composition of the two arrows as a new {@link Kleisli} arrow */ + @SuppressWarnings("overloads") default > Kleisli andThen(Kleisli after) { return a -> apply(a).flatMap(after).coerce(); } @@ -37,6 +38,7 @@ default > Kleisli andThen(Kleisli the {@link Monad} instance to flatMap with this arrow * @return the composition of the two arrows as a new {@link Kleisli} arrow */ + @SuppressWarnings("overloads") default > Kleisli compose(Kleisli before) { return z -> before.apply(z).flatMap(this).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java index 1f31e2ff3..9bd495727 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java @@ -54,14 +54,14 @@ public interface Applicative> extends Functor * using whatever application semantics the current applicative supports. This is useful for applicatives that * support lazy evaluation and early termination. * - * @param lazyAppFn the lazy other applicative instance * @param the resulting applicative parameter type + * @param lazyAppFn the lazy other applicative instance * @return the mapped applicative * @see com.jnape.palatable.lambda.adt.Maybe * @see com.jnape.palatable.lambda.adt.Either */ default Lazy> lazyZip( - Lazy, App>> lazyAppFn) { + Lazy, App>> lazyAppFn) { return lazyAppFn.fmap(this::zip); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index 5a08211dc..df6d857c2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -22,8 +22,9 @@ public Compose(Applicative, F> fga) { this.fga = fga; } + @SuppressWarnings("RedundantTypeArguments") public , FGA extends Applicative> FGA getCompose() { - return fga.fmap(Applicative::coerce).coerce(); + return fga.fmap(Applicative::coerce).coerce(); } /** @@ -47,16 +48,19 @@ public Compose pure(B b) { */ @Override public Compose zip(Applicative, Compose> appFn) { - return new Compose<>(fga.zip(appFn.>>coerce().getCompose().fmap(gFn -> g -> g.zip(gFn)))); + return new Compose<>(fga.zip(appFn.>>coerce() + .getCompose().fmap(gFn -> g -> g.zip(gFn)))); } /** * {@inheritDoc} + * + * @param lazyAppFn */ @Override public Lazy> lazyZip( - Lazy, Compose>> lazyAppFn) { - return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + Lazy, Compose>> lazyAppFn) { + return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative>::coerce); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index fdb81f8ef..220c41598 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -66,10 +66,13 @@ public Const zip(Applicative, Const Lazy> lazyZip(Lazy, Const>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + public Lazy> lazyZip( + Lazy, Const>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java index f5beb02c9..6ade25ffa 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java @@ -63,10 +63,13 @@ public Identity zip(Applicative, Identit /** * {@inheritDoc} + * + * @param lazyAppFn */ @Override - public Lazy> lazyZip(Lazy, Identity>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + public Lazy> lazyZip( + Lazy, Identity>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 7c21845a2..a9d735bc0 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -122,10 +122,12 @@ public final IO zip(Applicative, IO> /** * {@inheritDoc} + * + * @param lazyAppFn */ @Override - public Lazy> lazyZip(Lazy, IO>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + public Lazy> lazyZip(Lazy, IO>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java b/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java index 69b26f335..ed3308961 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java @@ -9,6 +9,7 @@ * * @see RateLimit */ +@SuppressWarnings("serial") public final class IterationInterruptedException extends RuntimeException { public IterationInterruptedException(InterruptedException cause) { diff --git a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java b/src/main/java/com/jnape/palatable/lambda/lens/Iso.java index 7d7be3d3c..bc3e76389 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/Iso.java @@ -50,7 +50,7 @@ * @param the smaller type for mirrored focusing */ @FunctionalInterface -public interface Iso extends LensLike { +public interface Iso extends LensLike> {

+ * While any two {@link com.jnape.palatable.lambda.functor.Functor functors} and any two + * {@link Applicative applicatives} can be composed in general, the same is not true in general of any two + * {@link Monad monads}. However, there exist {@link Monad monads} that do compose, in general, with any other + * {@link Monad}, provided that they are embedded inside the other {@link Monad}. When this is the case, they can offer + * implementations of {@link Monad#pure pure} and {@link Monad#flatMap(Function) flatMap} for free, simply by relying + * on the outer {@link Monad monad's} implementation of both, as well as their own privileged knowledge about how to + * merge the nested {@link Monad#flatMap(Function) flatMap} call. + *

+ * The term "monad transformer" describes a particular encoding of monadic composition. Because this general composition + * of a particular {@link Monad} with any other {@link Monad} relies on privileged knowledge about the embedded + * {@link Monad}, the {@link MonadT transformer} representing this compositions is described from the embedded + * {@link Monad monad's} perspective (e.g. {@link MaybeT} describing the embedding + * {@link Monad}<{@link com.jnape.palatable.lambda.adt.Maybe}<A>>). + *

+ * Additionally, monad transformers connected by compatible {@link Monad monads} also compose. When two or more monad + * transformers are composed, this is generally referred to as a "monad transformer stack". + *

+ * For more information, read more about + * monad transformers. + * + * @param the outer {@link Monad monad} + * @param the inner {@link Monad monad} + * @param the carrier type + * @see MaybeT + */ +public interface MonadT, G extends Monad, A> + extends Monad> { + + /** + * Extract out the composed monad out of this transformer. + * + * @param the inferred embedded monad + * @param the inferred composed monad + * @return the composed monad + */ + , FGA extends Monad> FGA run(); + + /** + * {@inheritDoc} + */ + @Override + MonadT flatMap(Function>> f); + + /** + * {@inheritDoc} + */ + @Override + MonadT pure(B b); + + /** + * {@inheritDoc} + */ + @Override + default MonadT fmap(Function fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadT zip(Applicative, MonadT> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Lazy> lazyZip( + Lazy, MonadT>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadT discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadT discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/MaybeTTest.java new file mode 100644 index 000000000..f39c40ff1 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/MaybeTTest.java @@ -0,0 +1,41 @@ +package com.jnape.palatable.lambda.monad.transformer; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.transformer.MaybeT.maybeT; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class MaybeTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public Subjects, Integer>> testSubject() { + return subjects(maybeT(right(just(1))), + maybeT(right(nothing())), + maybeT(left("foo"))); + } + + @Test + public void lazyZip() { + assertEquals(maybeT(right(just(2))), + maybeT(right(just(1))).lazyZip(lazy(maybeT(right(just(x -> x + 1))))).value()); + assertEquals(maybeT(left("foo")), + maybeT(left("foo")).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } +} \ No newline at end of file From ea2cc49f963a5f7a2477ee8cbf943d9c6c35c32b Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 17 Apr 2019 20:10:40 -0500 Subject: [PATCH 121/348] Endo, a monoid for fn1 using composition --- CHANGELOG.md | 1 + .../palatable/lambda/monoid/builtin/Endo.java | 57 +++++++++++++++++++ .../lambda/semigroup/builtin/EndoTest.java | 21 +++++++ 3 files changed, 79 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java create mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/EndoTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index bf372699b..753f944bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ might need to be reworked, and subtyping is obviously no longer supported. - `Applicative#lazyZip`, for zipping two applicatives in a way that might not require evaluation of one applicative - `MonadT`, a general interface representing monad transformers - `MaybeT`, a monad transformer for `Maybe` +- `Endo`, a monoid formed by `Fn1` under composition ## [3.3.0] - 2019-02-18 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java new file mode 100644 index 000000000..a5f1fcc0d --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java @@ -0,0 +1,57 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.monoid.Monoid; + +import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; + +/** + * A {@link Monoid} formed by {@link Fn1} under composition. + * + * @param the input/output type to the {@link Fn1} + */ +public final class Endo implements Monoid> { + + private static final Endo INSTANCE = new Endo<>(); + + private Endo() { + } + + @Override + public Fn1 identity() { + return id(); + } + + public A apply(Fn1 f, Fn1 g, A a) { + return apply(f, g).apply(a); + } + + @Override + public Fn1 apply(Fn1 f, Fn1 g) { + return f.fmap(g); + } + + @Override + public Fn2, A, A> apply(Fn1 f) { + return fn2(Monoid.super.apply(f)); + } + + @SuppressWarnings("unchecked") + public static Endo endo() { + return (Endo) INSTANCE; + } + + public static Fn2, A, A> endo(Fn1 f) { + return Endo.endo().apply(f); + } + + public static Fn1 endo(Fn1 f, Fn1 g) { + return endo(f).apply(g); + } + + public static A endo(Fn1 f, Fn1 g, A a) { + return endo(f, g).apply(a); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/EndoTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/EndoTest.java new file mode 100644 index 000000000..4da982462 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/EndoTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.monoid.builtin.Endo; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class EndoTest { + + @Test + public void identity() { + assertEquals((Integer) 1, Endo.endo().identity().apply(1)); + } + + @Test + public void semigroup() { + assertEquals((Integer) 2, Endo.endo().apply(x -> x + 1, x -> x + 1).apply(0)); + assertEquals((Integer) 2, Endo.endo().apply(x -> x + 1, x -> x + 1, 0)); + assertEquals((Integer) 2, Endo.endo(x -> x + 1, x -> x + 1, 0)); + } +} \ No newline at end of file From 0b7a3f2ec104aedda73bc6a644ea9319ed657728 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 17 Apr 2019 21:48:16 -0500 Subject: [PATCH 122/348] EItherT, a monad transformer for Either --- CHANGELOG.md | 1 + .../lambda/monad/transformer/MonadT.java | 1 + .../monad/transformer/builtin/EitherT.java | 121 ++++++++++++++++++ .../transformer/{ => builtin}/MaybeT.java | 3 +- .../transformer/builtin/EitherTTest.java | 39 ++++++ .../transformer/{ => builtin}/MaybeTTest.java | 5 +- 6 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java rename src/main/java/com/jnape/palatable/lambda/monad/transformer/{ => builtin}/MaybeT.java (96%) create mode 100644 src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java rename src/test/java/com/jnape/palatable/lambda/monad/transformer/{ => builtin}/MaybeTTest.java (87%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 753f944bf..284d3bfbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ might need to be reworked, and subtyping is obviously no longer supported. - `Applicative#lazyZip`, for zipping two applicatives in a way that might not require evaluation of one applicative - `MonadT`, a general interface representing monad transformers - `MaybeT`, a monad transformer for `Maybe` +- `EitherT`, a monad transformer for `Either` - `Endo`, a monoid formed by `Fn1` under composition ## [3.3.0] - 2019-02-18 diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java index 8098d2ba6..1afb4d426 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT; import java.util.function.Function; diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java new file mode 100644 index 000000000..592bd6b9f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -0,0 +1,121 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Compose; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import java.util.Objects; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; + +/** + * A {@link MonadT monad transformer} for {@link Either}. + * + * @param the outer {@link Monad} + * @param the left type + * @param the right type + */ +public final class EitherT, L, R> implements MonadT, R> { + + private final Monad, M> melr; + + private EitherT(Monad, M> melr) { + this.melr = melr; + } + + /** + * {@inheritDoc} + */ + @Override + public >, FGA extends Monad> FGA run() { + return melr.fmap(Either::coerce).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT flatMap(Function, ?>>> f) { + return eitherT(melr.flatMap(lr -> lr.match(l -> melr.pure(left(l)), + r -> f.apply(r).>coerce().run()))); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT pure(R2 r2) { + return eitherT(melr.pure(right(r2))); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT fmap(Function fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT zip( + Applicative, MonadT, ?>> appFn) { + return MonadT.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, MonadT, ?>>> lazyAppFn) { + return new Compose<>(melr) + .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( + maybeT.>>coerce() + .>, + Monad>, M>>run()))) + .fmap(compose -> eitherT(compose.getCompose())); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT discardL(Applicative, ?>> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT discardR(Applicative, ?>> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + @Override + public boolean equals(Object other) { + return other instanceof EitherT && Objects.equals(melr, ((EitherT) other).melr); + } + + @Override + public int hashCode() { + return Objects.hash(melr); + } + + @Override + public String toString() { + return "EitherT{melr=" + melr + '}'; + } + + public static , L, R> EitherT eitherT(Monad, M> melr) { + return new EitherT<>(melr); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java similarity index 96% rename from src/main/java/com/jnape/palatable/lambda/monad/transformer/MaybeT.java rename to src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index afbf56721..3d765ad1b 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -1,10 +1,11 @@ -package com.jnape.palatable.lambda.monad.transformer; +package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; import java.util.Objects; import java.util.function.Function; diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java new file mode 100644 index 000000000..b5d717b69 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java @@ -0,0 +1,39 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.eitherT; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class EitherTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public Subjects, String, Integer>> testSubject() { + return subjects(eitherT(new Identity<>(left("foo"))), eitherT(new Identity<>(right(1)))); + } + + @Test + public void lazyZip() { + assertEquals(eitherT(just(right(2))), + eitherT(just(right(1))).lazyZip(lazy(eitherT(just(right(x -> x + 1))))).value()); + assertEquals(eitherT(nothing()), + eitherT(nothing()).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java similarity index 87% rename from src/test/java/com/jnape/palatable/lambda/monad/transformer/MaybeTTest.java rename to src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java index f39c40ff1..8060ce8b3 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/MaybeTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java @@ -1,6 +1,7 @@ -package com.jnape.palatable.lambda.monad.transformer; +package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -15,7 +16,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; -import static com.jnape.palatable.lambda.monad.transformer.MaybeT.maybeT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.maybeT; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; From bf890a27eef62b86f0022aa057caaf2b3e54d65f Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 19 Apr 2019 17:22:28 -0500 Subject: [PATCH 123/348] Adding the State monad --- CHANGELOG.md | 1 + .../lambda/functor/builtin/State.java | 215 ++++++++++++++++++ .../lambda/functor/builtin/StateTest.java | 83 +++++++ 3 files changed, 299 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 284d3bfbf..f00e30a94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ might need to be reworked, and subtyping is obviously no longer supported. - `MaybeT`, a monad transformer for `Maybe` - `EitherT`, a monad transformer for `Either` - `Endo`, a monoid formed by `Fn1` under composition +- `State`, the state `Monad` ## [3.3.0] - 2019-02-18 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java new file mode 100644 index 000000000..68de3685d --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java @@ -0,0 +1,215 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; + +/** + * The state {@link Monad}, useful for iteratively building up state and state-contextualized result. + *

+ * For more information, read about the + * state monad. + * + * @param the state type + * @param the result type + */ +public final class State implements Monad> { + + private final Fn1> stateFn; + + private State(Fn1> stateFn) { + this.stateFn = stateFn; + } + + /** + * Run the stateful computation, returning a {@link Tuple2} of the result and the final state. + * + * @param s the initial state + * @return a {@link Tuple2} of the result and the final state. + */ + public Tuple2 run(S s) { + return stateFn.apply(s).into(HList::tuple); + } + + /** + * Run the stateful computation, returning the result. + * + * @param s the initial state + * @return the result + */ + public A eval(S s) { + return run(s)._1(); + } + + /** + * Run the stateful computation, returning the final state. + * + * @param s the initial state + * @return the final state + */ + public S exec(S s) { + return run(s)._2(); + } + + /** + * Map both the result and the final state to a new result and final state. + * + * @param fn the mapping function + * @param the potentially new final state type + * @return the mapped {@link State} + */ + public State mapState(Fn1, ? extends Product2> fn) { + return state(s -> fn.apply(run(s))); + } + + /** + * Map the final state to a new final state using the provided function. + * + * @param fn the state-mapping function + * @return the mapped {@link State} + */ + public State withState(Fn1 fn) { + return state(s -> run(fn.apply(s))); + } + + /** + * {@inheritDoc} + */ + @Override + public State flatMap(Function>> f) { + return state(s -> run(s).into((a, s2) -> f.apply(a).>coerce().run(s2))); + } + + /** + * {@inheritDoc} + */ + @Override + public State pure(B b) { + return state(s -> tuple(b, s)); + } + + /** + * {@inheritDoc} + */ + @Override + public State fmap(Function fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public State zip(Applicative, State> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, State>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + public State discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public State discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * Create a {@link State} that simply returns back the initial state as both the result and the final state + * + * @param the state and result type + * @return the new {@link State} instance + */ + @SuppressWarnings("RedundantTypeArguments") + public static State get() { + return new State<>(Tuple2::fill); + } + + /** + * Create a {@link State} that ignores its initial state, returning a {@link Unit} result and s as its + * final state. + * + * @param s the final state + * @param the state type + * @return the new {@link State} instance + */ + public static State put(S s) { + return new State<>(constantly(tuple(UNIT, s))); + } + + /** + * Create a {@link State} that maps its initial state into its result, but leaves the initial state unchanged. + * + * @param fn the mapping function + * @param the state type + * @param the result type + * @return the new {@link State} instance + */ + public static State gets(Fn1 fn) { + return state(both(fn, id())); + } + + /** + * Create a {@link State} that maps its initial state into its final state, returning a {@link Unit} result type. + * + * @param fn the mapping function + * @param the state type + * @return the new {@link State} instance + */ + public static State modify(Fn1 fn) { + return state(both(constantly(UNIT), fn)); + } + + /** + * Create a {@link State} from stateFn, a function that maps an initial state into a result and a final + * state. + * + * @param stateFn the state function + * @param the state type + * @param the result type + * @return the new {@link State} instance + */ + public static State state(Fn1> stateFn) { + return new State<>(stateFn.fmap(into(HList::tuple))); + } + + /** + * Create a {@link State} that returns a as its result and its initial state as its final state. + * + * @param a the result + * @param the state type + * @param the result type + * @return the new {@link State} instance + */ + public static State state(A a) { + return gets(constantly(a)); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java new file mode 100644 index 000000000..f2071a27e --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java @@ -0,0 +1,83 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.adt.product.Product2.product; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class StateTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public EquatableM, Unit> testSubject() { + return new EquatableM<>(State.get(), state -> state.run(UNIT).into(HList::tuple)); + } + + @Test + public void eval() { + State state = State.put(0); + assertEquals(state.run(1)._1(), state.eval(1)); + } + + @Test + public void exec() { + State state = State.put(0); + assertEquals(state.run(1)._2(), state.exec(1)); + } + + @Test + public void get() { + assertEquals(tuple(1, 1), State.get().run(1)); + } + + @Test + public void put() { + assertEquals(tuple(UNIT, 1), State.put(1).run(1)); + } + + @Test + public void gets() { + assertEquals(tuple(0, "0"), State.gets(Integer::parseInt).run("0")); + } + + @Test + public void modify() { + assertEquals(tuple(UNIT, 1), State.modify(x -> x + 1).run(0)); + } + + @Test + public void state() { + assertEquals(tuple(1, UNIT), State.state(1).run(UNIT)); + assertEquals(tuple(1, -1), State.state(x -> product(x + 1, x - 1)).run(0)); + } + + @Test + public void stateAccumulation() { + State counter = State.get().flatMap(i -> State.put(i + 1).discardL(State.state(i))); + assertEquals(tuple(0, 1), counter.run(0)); + } + + @Test + public void withState() { + State modified = State.get().withState(x -> x + 1); + assertEquals(tuple(1, 1), modified.run(0)); + } + + @Test + public void mapState() { + State modified = State.get().mapState(into((a, s) -> product(a + 1, s + 2))); + assertEquals(tuple(1, 2), modified.run(0)); + } +} \ No newline at end of file From 2f04d024cb7c093c27499e8eb1a9c312624dd6ae Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 19 Apr 2019 17:37:28 -0500 Subject: [PATCH 124/348] Adding Gitter badge to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d4c933638..476f89ebc 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ====== [![Build Status](https://img.shields.io/travis/palatable/lambda/master.svg)](https://travis-ci.org/palatable/lambda) [![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda) +[![Join the chat at https://gitter.im/palatable/lambda](https://badges.gitter.im/palatable/lambda.svg)](https://gitter.im/palatable/lambda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Functional patterns for Java From 5186c1164bdd49bb095a012c2e5a8a9f544fdaed Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 19 Apr 2019 18:06:14 -0500 Subject: [PATCH 125/348] Even more new javac warnings --- .../lambda/iteration/MappingIterable.java | 15 ++++++++------- .../lambda/iteration/UnfoldingIterator.java | 1 - .../palatable/lambda/functor/BifunctorTest.java | 4 ++-- .../palatable/lambda/functor/ProfunctorTest.java | 4 ++-- .../lambda/iteration/DroppingIteratorTest.java | 2 +- .../lambda/iteration/ImmutableIteratorTest.java | 4 ++-- .../lambda/iteration/InfiniteIteratorTest.java | 4 ++-- .../lambda/iteration/ReversingIteratorTest.java | 4 +++- .../lambda/iteration/RewindableIteratorTest.java | 2 +- src/test/java/testsupport/Mocking.java | 5 +++-- .../InvocationRecordingBifunctor.java | 8 ++++---- .../InvocationRecordingProfunctor.java | 8 ++++---- .../exceptions/OutOfScopeException.java | 1 + .../matchers/FiniteIterableMatcher.java | 4 ++-- .../testsupport/matchers/IterableMatcher.java | 13 +++++++------ 15 files changed, 42 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java b/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java index 1730a6838..b65510f55 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java @@ -9,15 +9,15 @@ import static java.util.Collections.singletonList; public final class MappingIterable implements Iterable { - private final Iterable as; - private final List mappers; + private final Iterable as; + private final List> mappers; @SuppressWarnings("unchecked") public MappingIterable(Function fn, Iterable as) { - List mappers = new ArrayList<>(singletonList(fn)); - while (as instanceof MappingIterable) { + List> mappers = new ArrayList<>(singletonList(fn)); + while (as instanceof MappingIterable) { MappingIterable nested = (MappingIterable) as; - as = (Iterable) nested.as; + as = (Iterable) nested.as; mappers.addAll(0, nested.mappers); } this.as = as; @@ -27,7 +27,8 @@ public MappingIterable(Function fn, Iterable as) { @Override @SuppressWarnings("unchecked") public Iterator iterator() { - Function fnComposedOnTheHeap = o -> foldLeft((x, fn) -> fn.apply(x), o, mappers); - return new MappingIterator<>(fnComposedOnTheHeap, as.iterator()); + Function fnComposedOnTheHeap = a -> foldLeft((x, fn) -> ((Function) fn).apply(x), + a, mappers); + return new MappingIterator<>((Function) fnComposedOnTheHeap, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java index 418121c7c..0d014df81 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java @@ -27,7 +27,6 @@ public boolean hasNext() { } @Override - @SuppressWarnings("ConstantConditions") public A next() { if (!hasNext()) throw new NoSuchElementException(); diff --git a/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java b/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java index 4cb93cf08..bef359ebc 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java @@ -14,7 +14,7 @@ public class BifunctorTest { @Test public void biMapLUsesIdentityForRightBiMapFunction() { - AtomicReference rightInvocation = new AtomicReference<>(); + AtomicReference> rightInvocation = new AtomicReference<>(); Bifunctor> bifunctor = new InvocationRecordingBifunctor<>(new AtomicReference<>(), rightInvocation); bifunctor.biMapL(String::toUpperCase); @@ -23,7 +23,7 @@ public void biMapLUsesIdentityForRightBiMapFunction() { @Test public void biMapRUsesIdentityForLeftBiMapFunction() { - AtomicReference leftInvocation = new AtomicReference<>(); + AtomicReference> leftInvocation = new AtomicReference<>(); Bifunctor> bifunctor = new InvocationRecordingBifunctor<>(leftInvocation, new AtomicReference<>()); bifunctor.biMapR(String::valueOf); diff --git a/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java b/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java index f2fb6980d..a6650b32a 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java @@ -14,7 +14,7 @@ public class ProfunctorTest { @Test public void diMapLUsesIdentityForRightDiMapFunction() { - AtomicReference rightInvocation = new AtomicReference<>(); + AtomicReference> rightInvocation = new AtomicReference<>(); Profunctor> profunctor = new InvocationRecordingProfunctor<>(new AtomicReference<>(), rightInvocation); profunctor.diMapL(Object::toString); @@ -23,7 +23,7 @@ public void diMapLUsesIdentityForRightDiMapFunction() { @Test public void diMapRUsesIdentityForLeftDiMapFunction() { - AtomicReference leftInvocation = new AtomicReference<>(); + AtomicReference> leftInvocation = new AtomicReference<>(); Profunctor> profunctor = new InvocationRecordingProfunctor<>(leftInvocation, new AtomicReference<>()); profunctor.diMapR(String::valueOf); diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java index 0e28a2dd2..9bbdad7ad 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java @@ -17,7 +17,7 @@ public class DroppingIteratorTest { @Mock private Iterator iterator; - private DroppingIterator droppingIterator; + private DroppingIterator droppingIterator; @Before public void setUp() { diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java index d1ffc6ebd..da73c4aef 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java @@ -7,11 +7,11 @@ public class ImmutableIteratorTest { - private ImmutableIterator immutableIterator; + private ImmutableIterator immutableIterator; @Before public void setUp() { - immutableIterator = new ImmutableIterator() { + immutableIterator = new ImmutableIterator() { @Override public boolean hasNext() { throw outOfScope(); diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java index 9d9f8abd5..7ce772cf6 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java @@ -9,11 +9,11 @@ public class InfiniteIteratorTest { - private InfiniteIterator infiniteIterator; + private InfiniteIterator infiniteIterator; @Before public void setUp() { - infiniteIterator = new InfiniteIterator() { + infiniteIterator = new InfiniteIterator() { @Override public Object next() { throw outOfScope(); diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java index 754345bfb..391bcfb26 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java @@ -22,7 +22,7 @@ public class ReversingIteratorTest { @Mock private Iterator iterator; - private ReversingIterator reversingIterator; + private ReversingIterator reversingIterator; @Before public void setUp() { @@ -47,6 +47,7 @@ public void reversesIterator() { } @Test + @SuppressWarnings("ResultOfMethodCallIgnored") public void doesNotReverseUntilNextIsCalled() { reversingIterator.hasNext(); verify(iterator, never()).next(); @@ -63,6 +64,7 @@ public void doesNotHaveNextIfFinishedReversingIterator() { } @Test + @SuppressWarnings("ResultOfMethodCallIgnored") public void neverInteractsWithIteratorAgainAfterInitialReverse() { mockIteratorToHaveValues(iterator, 1, 2, 3); diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java index 3e1498b90..a8bee457c 100644 --- a/src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java @@ -18,7 +18,7 @@ public class RewindableIteratorTest { @Mock private Iterator iterator; - private RewindableIterator rewindableIterator; + private RewindableIterator rewindableIterator; @Before public void setUp() { diff --git a/src/test/java/testsupport/Mocking.java b/src/test/java/testsupport/Mocking.java index 041105a7b..cbc86cd7a 100644 --- a/src/test/java/testsupport/Mocking.java +++ b/src/test/java/testsupport/Mocking.java @@ -18,8 +18,9 @@ public static Iterable mockIterable() { } @SafeVarargs - public static void mockIteratorToHaveValues(Iterator iterator, T... values) { - Iterator real = asList(values).iterator(); + @SuppressWarnings("varargs") + public static void mockIteratorToHaveValues(Iterator iterator, T... values) { + Iterator real = asList(values).iterator(); when(iterator.hasNext()).then(delegateTo(real)); when(iterator.next()).then(delegateTo(real)); diff --git a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java index 92565e2de..65ff38cba 100644 --- a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java +++ b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java @@ -6,11 +6,11 @@ import java.util.function.Function; public final class InvocationRecordingBifunctor implements Bifunctor> { - private final AtomicReference leftFn; - private final AtomicReference rightFn; + private final AtomicReference> leftFn; + private final AtomicReference> rightFn; - public InvocationRecordingBifunctor(AtomicReference leftFn, - AtomicReference rightFn) { + public InvocationRecordingBifunctor(AtomicReference> leftFn, + AtomicReference> rightFn) { this.leftFn = leftFn; this.rightFn = rightFn; } diff --git a/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java b/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java index ac9e53fba..28c34ee0f 100644 --- a/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java +++ b/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java @@ -6,11 +6,11 @@ import java.util.function.Function; public final class InvocationRecordingProfunctor implements Profunctor> { - private final AtomicReference leftFn; - private final AtomicReference rightFn; + private final AtomicReference> leftFn; + private final AtomicReference> rightFn; - public InvocationRecordingProfunctor(AtomicReference leftFn, - AtomicReference rightFn) { + public InvocationRecordingProfunctor(AtomicReference> leftFn, + AtomicReference> rightFn) { this.leftFn = leftFn; this.rightFn = rightFn; } diff --git a/src/test/java/testsupport/exceptions/OutOfScopeException.java b/src/test/java/testsupport/exceptions/OutOfScopeException.java index b723b7d4c..8e8f0e4b6 100644 --- a/src/test/java/testsupport/exceptions/OutOfScopeException.java +++ b/src/test/java/testsupport/exceptions/OutOfScopeException.java @@ -1,5 +1,6 @@ package testsupport.exceptions; +@SuppressWarnings("serial") public class OutOfScopeException extends RuntimeException { public OutOfScopeException(String s) { diff --git a/src/test/java/testsupport/matchers/FiniteIterableMatcher.java b/src/test/java/testsupport/matchers/FiniteIterableMatcher.java index 609f54d51..7f5b57d58 100644 --- a/src/test/java/testsupport/matchers/FiniteIterableMatcher.java +++ b/src/test/java/testsupport/matchers/FiniteIterableMatcher.java @@ -3,7 +3,7 @@ import org.hamcrest.BaseMatcher; import org.hamcrest.Description; -public class FiniteIterableMatcher extends BaseMatcher { +public class FiniteIterableMatcher extends BaseMatcher> { @Override public boolean matches(Object item) { @@ -21,7 +21,7 @@ public void describeMismatch(Object item, Description description) { } @SuppressWarnings("UnusedDeclaration") - private boolean supportsLessThanInfiniteIterations(Iterable iterable) { + private boolean supportsLessThanInfiniteIterations(Iterable iterable) { long sufficientlyInfinite = 1000000; long elementsIterated = 0; for (Object ignored : iterable) diff --git a/src/test/java/testsupport/matchers/IterableMatcher.java b/src/test/java/testsupport/matchers/IterableMatcher.java index 5313e70af..5478e46e3 100644 --- a/src/test/java/testsupport/matchers/IterableMatcher.java +++ b/src/test/java/testsupport/matchers/IterableMatcher.java @@ -37,16 +37,16 @@ public void describeMismatch(Object item, Description description) { super.describeMismatch(item, description); } - private boolean iterablesIterateSameElementsInOrder(Iterable expected, Iterable actual) { - Iterator actualIterator = actual.iterator(); - Iterator expectedIterator = expected.iterator(); + private boolean iterablesIterateSameElementsInOrder(Iterable expected, Iterable actual) { + Iterator actualIterator = actual.iterator(); + Iterator expectedIterator = expected.iterator(); while (expectedIterator.hasNext() && actualIterator.hasNext()) { Object nextExpected = expectedIterator.next(); Object nextActual = actualIterator.next(); if (nextExpected instanceof Iterable && nextActual instanceof Iterable) { - if (!iterablesIterateSameElementsInOrder((Iterable) nextExpected, (Iterable) nextActual)) + if (!iterablesIterateSameElementsInOrder((Iterable) nextExpected, (Iterable) nextActual)) return false; } else if (!reflectionEquals(nextExpected, nextActual)) return false; @@ -55,9 +55,9 @@ private boolean iterablesIterateSameElementsInOrder(Iterable expected, Iterable return actualIterator.hasNext() == expectedIterator.hasNext(); } - private String stringify(Iterable iterable) { + private String stringify(Iterable iterable) { StringBuilder stringBuilder = new StringBuilder().append("["); - Iterator iterator = iterable.iterator(); + Iterator iterator = iterable.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); if (next instanceof Iterable) @@ -71,6 +71,7 @@ private String stringify(Iterable iterable) { } @SafeVarargs + @SuppressWarnings("varargs") public static IterableMatcher iterates(E... es) { return new IterableMatcher<>(asList(es)); } From a52d18eb035bd10c32e5fdefc8ef838c502dea71 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 19 Apr 2019 18:21:53 -0500 Subject: [PATCH 126/348] Adding IdentityT, a monad transformer for Identity --- CHANGELOG.md | 1 + .../monad/transformer/builtin/EitherT.java | 10 ++ .../monad/transformer/builtin/IdentityT.java | 124 ++++++++++++++++++ .../monad/transformer/builtin/MaybeT.java | 4 +- .../transformer/builtin/IdentityTTest.java | 37 ++++++ 5 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f00e30a94..27fc48fbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ might need to be reworked, and subtyping is obviously no longer supported. - `MonadT`, a general interface representing monad transformers - `MaybeT`, a monad transformer for `Maybe` - `EitherT`, a monad transformer for `Either` +- `IdentityT`, a monad transformer for `Identity` - `Endo`, a monoid formed by `Fn1` under composition - `State`, the state `Monad` diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java index 592bd6b9f..3b23327d9 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -115,6 +115,16 @@ public String toString() { return "EitherT{melr=" + melr + '}'; } + /** + * Static factory method for lifting a {@link Monad}<{@link Either}<L, R>, M> into an + * {@link EitherT}. + * + * @param melr the {@link Monad}<{@link Either}<L, R>, M> + * @param the outer {@link Monad} unification parameter + * @param the left type + * @param the right type + * @return the {@link EitherT} + */ public static , L, R> EitherT eitherT(Monad, M> melr) { return new EitherT<>(melr); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java new file mode 100644 index 000000000..932680c8b --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java @@ -0,0 +1,124 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Compose; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import java.util.Objects; +import java.util.function.Function; + +/** + * A {@link MonadT monad transformer} for {@link Identity}. + * + * @param the outer {@link Monad} + * @param the carrier type + */ +public final class IdentityT, A> implements MonadT, A> { + + private final Monad, M> mia; + + private IdentityT(Monad, M> mia) { + this.mia = mia; + } + + /** + * {@inheritDoc} + */ + @Override + public >, FGA extends Monad> FGA run() { + return mia.fmap(Identity::coerce).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT flatMap(Function, ?>>> f) { + return identityT(mia.flatMap(identityA -> f.apply(identityA.runIdentity()).>coerce().run())); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT pure(B b) { + return identityT(mia.pure(new Identity<>(b))); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT fmap(Function fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT zip(Applicative, MonadT, ?>> appFn) { + return MonadT.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, MonadT, ?>>> lazyAppFn) { + return new Compose<>(mia) + .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( + maybeT.>>coerce() + .>, + Monad>, M>>run()))) + .fmap(compose -> identityT(compose.getCompose())); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT discardL(Applicative, ?>> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT discardR(Applicative, ?>> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + @Override + public boolean equals(Object other) { + return other instanceof IdentityT && Objects.equals(mia, ((IdentityT) other).mia); + } + + @Override + public int hashCode() { + return Objects.hash(mia); + } + + @Override + public String toString() { + return "IdentityT{mia=" + mia + '}'; + } + + /** + * Static factory method for lifting a {@link Monad}<{@link Identity}<A>, M> into a + * {@link IdentityT}. + * + * @param mia the {@link Monad}<{@link Identity}<A>, M> + * @param the outer {@link Monad} unification parameter + * @param the carrier type + * @return the new {@link IdentityT}. + */ + public static , A> IdentityT identityT(Monad, M> mia) { + return new IdentityT<>(mia); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index 3d765ad1b..f7d72406a 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -116,10 +116,10 @@ public String toString() { } /** - * Static factory method for lifting a {@link Monad}<{@link Maybe}<A>> into a + * Static factory method for lifting a {@link Monad}<{@link Maybe}<A>, M> into a * {@link MaybeT}. * - * @param mma the {@link Monad}<{@link Maybe}<A>> + * @param mma the {@link Monad}<{@link Maybe}<A>, M> * @param the outer {@link Monad} unification parameter * @param the carrier type * @return the {@link MaybeT} diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java new file mode 100644 index 000000000..fb9a6629d --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java @@ -0,0 +1,37 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT.identityT; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class IdentityTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public IdentityT, Integer> testSubject() { + return identityT(just(new Identity<>(1))); + } + + @Test + public void lazyZip() { + assertEquals(identityT(just(new Identity<>(2))), + identityT(just(new Identity<>(1))) + .lazyZip(lazy(identityT(just(new Identity<>(x -> x + 1))))).value()); + assertEquals(identityT(nothing()), + identityT(nothing()).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } +} \ No newline at end of file From e944b018f540a6bb9acd77cb379e9438f01fb4f1 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 19 Apr 2019 18:25:20 -0500 Subject: [PATCH 127/348] Adding Downcast, a first-class version of Applicative#coerce --- CHANGELOG.md | 1 + .../functions/builtin/fn1/Downcast.java | 32 +++++++++++++++++++ .../functions/builtin/fn1/DowncastTest.java | 28 ++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 27fc48fbe..138ae47c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ might need to be reworked, and subtyping is obviously no longer supported. - `IdentityT`, a monad transformer for `Identity` - `Endo`, a monoid formed by `Fn1` under composition - `State`, the state `Monad` +- `Downcast`, a function supporting unchecked down-casting ## [3.3.0] - 2019-02-18 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java new file mode 100644 index 000000000..c7efde762 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java @@ -0,0 +1,32 @@ +package com.jnape.palatable.lambda.functions.builtin.fn1; + +import com.jnape.palatable.lambda.functions.Fn1; + +/** + * Covariantly cast a value of type B to a value of subtype A. Unsafe. + * + * @param the subtype + * @param the supertype + */ +public final class Downcast implements Fn1 { + + private static final Downcast INSTANCE = new Downcast<>(); + + private Downcast() { + } + + @Override + @SuppressWarnings("unchecked") + public A apply(B b) { + return (A) b; + } + + @SuppressWarnings("unchecked") + public static Downcast downcast() { + return (Downcast) INSTANCE; + } + + public static A downcast(B b) { + return Downcast.downcast().apply(b); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java new file mode 100644 index 000000000..b21e30b73 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java @@ -0,0 +1,28 @@ +package com.jnape.palatable.lambda.functions.builtin.fn1; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.Functor; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; + +public class DowncastTest { + + @Test + @SuppressWarnings("unused") + public void safeDowncast() { + CharSequence charSequence = "123"; + String s = downcast(charSequence); + + Functor> maybeInt = nothing(); + Maybe cast = downcast(maybeInt); + } + + @Test(expected = ClassCastException.class) + @SuppressWarnings({"JavacQuirks", "unused"}) + public void unsafeDowncast() { + CharSequence charSequence = "123"; + Integer explosion = downcast(charSequence); + } +} \ No newline at end of file From eeb1412ef3b1e7cdffac1926dd8a7c1e45e6937b Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 19 Apr 2019 18:28:35 -0500 Subject: [PATCH 128/348] Moving coerce to Functor --- .../java/com/jnape/palatable/lambda/adt/Try.java | 2 +- .../jnape/palatable/lambda/adt/choice/Choice2.java | 4 +++- .../jnape/palatable/lambda/adt/choice/Choice3.java | 4 +++- .../jnape/palatable/lambda/adt/choice/Choice4.java | 4 +++- .../jnape/palatable/lambda/adt/choice/Choice5.java | 3 ++- .../jnape/palatable/lambda/adt/choice/Choice6.java | 4 +++- .../jnape/palatable/lambda/adt/choice/Choice7.java | 4 +++- .../jnape/palatable/lambda/adt/choice/Choice8.java | 4 +++- .../jnape/palatable/lambda/functor/Applicative.java | 11 ----------- .../com/jnape/palatable/lambda/functor/Functor.java | 12 ++++++++++++ 10 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index e714739ed..4b0e24b19 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -206,7 +206,7 @@ public Try discardR(Applicative> appB) { AppTrav extends Applicative> AppTrav traverse(Function fn, Function pure) { return match(t -> pure.apply((TravB) failure(t)), - a -> fn.apply(a).fmap(Try::success).fmap(Applicative::coerce).coerce()); + a -> fn.apply(a).>fmap(Try::success).fmap(Applicative::coerce).coerce()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index b63ed4745..e16315de9 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -114,6 +115,7 @@ public Choice2 zip(Applicative, Choic /** * {@inheritDoc} + * * @param lazyAppFn */ @Override @@ -157,7 +159,7 @@ public final Choice2 flatMap(Function> AppTrav traverse(Function fn, Function pure) { return match(a -> pure.apply((TravB) a(a)), - b -> fn.apply(b).fmap(Choice2::b).fmap(Applicative::coerce).coerce()); + b -> fn.apply(b).>fmap(Choice2::b).fmap(Functor::coerce).coerce()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index c3d8d2697..953a0ca58 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple3; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -114,6 +115,7 @@ public Choice3 zip(Applicative, Ch /** * {@inheritDoc} + * * @param lazyAppFn */ @Override @@ -159,7 +161,7 @@ AppTrav extends Applicative> AppTrav traverse(Function pure) { return match(a -> pure.apply((TravB) Choice3.a(a)).coerce(), b -> pure.apply((TravB) Choice3.b(b)).coerce(), - c -> fn.apply(c).fmap(Choice3::c).fmap(Applicative::coerce).coerce()); + c -> fn.apply(c).>fmap(Choice3::c).fmap(Functor::coerce).coerce()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index a707afc69..8a2efdec7 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple4; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -115,6 +116,7 @@ public Choice4 zip(Applicative, /** * {@inheritDoc} + * * @param lazyAppFn */ @Override @@ -162,7 +164,7 @@ AppTrav extends Applicative> AppTrav traverse(Function pure.apply((TravB) Choice4.a(a)).coerce(), b -> pure.apply((TravB) Choice4.b(b)).coerce(), c -> pure.apply((TravB) Choice4.c(c)), - d -> fn.apply(d).fmap(Choice4::d).fmap(Applicative::coerce).coerce()); + d -> fn.apply(d).>fmap(Choice4::d).fmap(Functor::coerce).coerce()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index ed4b4a5b6..fb4a609f3 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -169,7 +169,8 @@ AppTrav extends Applicative> AppTrav traverse(Function pure.apply((TravB) Choice5.b(b)).coerce(), c -> pure.apply((TravB) Choice5.c(c)), d -> pure.apply((TravB) Choice5.d(d)), - e -> fn.apply(e).fmap(Choice5::e).fmap(Applicative::coerce).coerce()); + e -> fn.apply(e).>fmap(Choice5::e) + .fmap(Applicative::coerce).coerce()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index e3ab3d48f..c3696b1a4 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -123,6 +123,7 @@ public Choice6 zip( /** * {@inheritDoc} + * * @param lazyAppFn */ @Override @@ -175,7 +176,8 @@ AppTrav extends Applicative> AppTrav traverse(Function pure.apply((TravB) Choice6.c(c)), d -> pure.apply((TravB) Choice6.d(d)), e -> pure.apply((TravB) Choice6.e(e)), - f -> fn.apply(f).fmap(Choice6::f).fmap(Applicative::coerce).coerce()); + f -> fn.apply(f).>fmap(Choice6::f) + .fmap(Applicative::coerce).coerce()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index 1348293a5..4f6c2708c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -126,6 +126,7 @@ public Choice7 zip( /** * {@inheritDoc} + * * @param lazyAppFn */ @Override @@ -180,7 +181,8 @@ AppTrav extends Applicative> AppTrav traverse(Function pure.apply((TravB) Choice7.d(d)), e -> pure.apply((TravB) Choice7.e(e)), f -> pure.apply((TravB) Choice7.f(f)), - g -> fn.apply(g).fmap(Choice7::g).fmap(Applicative::coerce).coerce()); + g -> fn.apply(g).>fmap(Choice7::g) + .fmap(Applicative::coerce).coerce()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index b0a70c530..28d47e689 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -119,6 +119,7 @@ public Choice8 zip( /** * {@inheritDoc} + * * @param lazyAppFn */ @Override @@ -175,7 +176,8 @@ AppTrav extends Applicative> AppTrav traverse(Function pure.apply((TravB) Choice8.e(e)), f -> pure.apply((TravB) Choice8.f(f)), g -> pure.apply((TravB) Choice8.g(g)), - h -> fn.apply(h).fmap(Choice8::h).fmap(Applicative::coerce).coerce()); + h -> fn.apply(h).>fmap(Choice8::h) + .fmap(Applicative::coerce).coerce()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java index 9bd495727..af08c2a00 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java @@ -93,15 +93,4 @@ default Applicative discardL(Applicative appB) { default Applicative discardR(Applicative appB) { return appB.zip(fmap(constantly())); } - - /** - * Convenience method for coercing this applicative instance into another concrete type. Unsafe. - * - * @param the concrete applicative instance to coerce this applicative to - * @return the coerced applicative - */ - @SuppressWarnings({"unchecked"}) - default > Concrete coerce() { - return (Concrete) this; - } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Functor.java b/src/main/java/com/jnape/palatable/lambda/functor/Functor.java index 7645f1013..49e5664cd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Functor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Functor.java @@ -4,6 +4,8 @@ import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; + /** * An interface for the generic covariant functorial operation map over some parameter A. * Functors are foundational to many of the classes provided by this library; generally, anything that can be thought of @@ -31,4 +33,14 @@ public interface Functor> { * @return a functor over B (the new parameter type) */ Functor fmap(Function fn); + + /** + * Convenience method for coercing this functor instance into another concrete type. Unsafe. + * + * @param the concrete functor instance to coerce this functor to + * @return the coerced functor + */ + default > Concrete coerce() { + return downcast(this); + } } From cc11576093339e43c677f84f15dd4cdd331e266e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 21 Apr 2019 14:27:08 -0500 Subject: [PATCH 129/348] Renaming Strong to Cartesian to better reflect the type of strength --- CHANGELOG.md | 1 + .../jnape/palatable/lambda/functions/Fn1.java | 14 ++--- .../specialized/checked/CheckedFn1.java | 4 +- .../palatable/lambda/functor/Cartesian.java | 53 +++++++++++++++++++ .../palatable/lambda/functor/Strong.java | 53 ------------------- .../palatable/lambda/functions/Fn1Test.java | 2 +- .../specialized/checked/CheckedFn1Test.java | 2 +- 7 files changed, 65 insertions(+), 64 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java delete mode 100644 src/main/java/com/jnape/palatable/lambda/functor/Strong.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 138ae47c4..fa7e60339 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ might need to be reworked, and subtyping is obviously no longer supported. - ***Breaking Change***: `FoldRight` now requires `Lazy` as part of its interface to support short-circuiting operations - ***Breaking Change***: Eliminated all raw types and java11 warnings. This required using capture in unification parameters for Functor and friends, so nearly every functor's type-signature changed. +- ***Breaking Change***: `Strong` is now called `Cartesian` to better reflect the type of strength - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 6384641a8..291a525d2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -2,7 +2,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Strong; +import com.jnape.palatable.lambda.functor.Cartesian; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -20,7 +20,7 @@ * @param The result type */ @FunctionalInterface -public interface Fn1 extends Monad>, Strong>, Function { +public interface Fn1 extends Monad>, Cartesian>, Function { /** * Invoke this function with the given argument. @@ -131,7 +131,7 @@ default Fn1 discardR(Applicative> appB) { */ @Override default Fn1 diMapL(Function fn) { - return (Fn1) Strong.super.diMapL(fn); + return (Fn1) Cartesian.super.diMapL(fn); } /** @@ -144,7 +144,7 @@ default Fn1 diMapL(Function fn) { */ @Override default Fn1 diMapR(Function fn) { - return (Fn1) Strong.super.diMapR(fn); + return (Fn1) Cartesian.super.diMapR(fn); } /** @@ -168,7 +168,7 @@ default Fn1 diMap(Function lFn, Function Fn1, Tuple2> strengthen() { + default Fn1, Tuple2> cartesian() { return t -> t.fmap(this); } @@ -177,12 +177,12 @@ default Fn1, Tuple2> strengthen() { */ @Override default Fn1> carry() { - return (Fn1>) Strong.super.carry(); + return (Fn1>) Cartesian.super.carry(); } @Override default Fn1 contraMap(Function fn) { - return (Fn1) Strong.super.contraMap(fn); + return (Fn1) Cartesian.super.contraMap(fn); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java index 4b5bd93a7..4fd589c2a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java @@ -112,8 +112,8 @@ default CheckedFn1 diMap(Function lFn, * {@inheritDoc} */ @Override - default CheckedFn1, Tuple2> strengthen() { - return Fn1.super.strengthen()::apply; + default CheckedFn1, Tuple2> cartesian() { + return Fn1.super.cartesian()::apply; } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java new file mode 100644 index 000000000..71f3afb5c --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java @@ -0,0 +1,53 @@ +package com.jnape.palatable.lambda.functor; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; + +import java.util.function.Function; + +/** + * {@link Profunctor} strength in the cartesian sense: p a b -> p (c, a) (c, b) for any type + * c. + * + * @param the type of the left parameter + * @param the type of the left parameter + * @param the unification parameter + * @see com.jnape.palatable.lambda.functions.Fn1 + */ +public interface Cartesian> extends Profunctor { + + /** + * Pair some type C to this profunctor's carrier types. + * + * @param the paired type + * @return the cartesian-strengthened profunctor + */ + Cartesian, Tuple2, S> cartesian(); + + /** + * Pair the covariantly-positioned carrier type with the contravariantly-positioned carrier type. This can be + * thought of as "carrying" or "inspecting" the left parameter. + * + * @return the profunctor with the first parameter carried + */ + default Cartesian, S> carry() { + return this.cartesian().contraMap(Tuple2::fill); + } + + @Override + Cartesian diMap(Function lFn, Function rFn); + + @Override + default Cartesian diMapL(Function fn) { + return (Cartesian) Profunctor.super.diMapL(fn); + } + + @Override + default Cartesian diMapR(Function fn) { + return (Cartesian) Profunctor.super.diMapR(fn); + } + + @Override + default Cartesian contraMap(Function fn) { + return (Cartesian) Profunctor.super.contraMap(fn); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Strong.java b/src/main/java/com/jnape/palatable/lambda/functor/Strong.java deleted file mode 100644 index 0be4c230d..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functor/Strong.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.jnape.palatable.lambda.functor; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; - -import java.util.function.Function; - -/** - * "Strong" {@link Profunctor profunctors} are profunctors that can be "strengthened" to preserve the pairing of an - * arbitrary type under dimap (p a b -> p (c, a) (c, b) for any type c). - * - * @param the type of the left parameter - * @param the type of the left parameter - * @param the unification parameter - * @see com.jnape.palatable.lambda.functions.Fn1 - */ -public interface Strong> extends Profunctor { - - /** - * Pair some type C to this profunctor's carrier types. - * - * @param the paired type - * @return the strengthened profunctor - */ - Strong, Tuple2, S> strengthen(); - - /** - * Pair the covariantly-positioned carrier type with the contravariantly-positioned carrier type. This can be - * thought of as "carrying" or "inspecting" the left parameter. - * - * @return the profunctor with the first parameter carried - */ - default Strong, S> carry() { - return this.strengthen().contraMap(Tuple2::fill); - } - - @Override - Strong diMap(Function lFn, Function rFn); - - @Override - default Strong diMapL(Function fn) { - return (Strong) Profunctor.super.diMapL(fn); - } - - @Override - default Strong diMapR(Function fn) { - return (Strong) Profunctor.super.diMapR(fn); - } - - @Override - default Strong contraMap(Function fn) { - return (Strong) Profunctor.super.contraMap(fn); - } -} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index 20074539b..80af42dc1 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -56,7 +56,7 @@ public void widen() { @Test public void strengthen() { Fn1 add1 = x -> x + 1; - assertEquals(tuple("a", 2), add1.strengthen().apply(tuple("a", 1))); + assertEquals(tuple("a", 2), add1.cartesian().apply(tuple("a", 1))); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java index a8818d684..c5b614755 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java @@ -22,7 +22,7 @@ public void assignment() { CheckedFn1 diMapL = parseInt.diMapL(id()); CheckedFn1 diMapR = parseInt.diMapR(id()); CheckedFn1 diMap = parseInt.diMap(id(), id()); - CheckedFn1, Tuple2> strengthen = parseInt.strengthen(); + CheckedFn1, Tuple2> strengthen = parseInt.cartesian(); CheckedFn1> carry = parseInt.carry(); CheckedFn1 contraMap = parseInt.contraMap(id()); CheckedFn1 compose = parseInt.compose(id()); From 1d2749f7368694e1309ad7d22ed8267609b83e06 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 21 Apr 2019 15:45:05 -0500 Subject: [PATCH 130/348] Cocartesian coproduct strength --- CHANGELOG.md | 1 + .../jnape/palatable/lambda/functions/Fn1.java | 31 ++++++++- .../palatable/lambda/functor/Cartesian.java | 25 +++---- .../palatable/lambda/functor/Cocartesian.java | 66 +++++++++++++++++++ .../palatable/lambda/functor/Profunctor.java | 3 + .../palatable/lambda/functions/Fn1Test.java | 18 ++++- 6 files changed, 130 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java diff --git a/CHANGELOG.md b/CHANGELOG.md index fa7e60339..faf352044 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ might need to be reworked, and subtyping is obviously no longer supported. - `Endo`, a monoid formed by `Fn1` under composition - `State`, the state `Monad` - `Downcast`, a function supporting unchecked down-casting +- `Cocartesian`, profunctorial strength in cocartesian coproduct terms ## [3.3.0] - 2019-02-18 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 291a525d2..680dc55eb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -1,8 +1,11 @@ package com.jnape.palatable.lambda.functions; +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cartesian; +import com.jnape.palatable.lambda.functor.Cocartesian; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -20,7 +23,11 @@ * @param The result type */ @FunctionalInterface -public interface Fn1 extends Monad>, Cartesian>, Function { +public interface Fn1 extends + Monad>, + Cartesian>, + Cocartesian>, + Function { /** * Invoke this function with the given argument. @@ -97,6 +104,7 @@ default Fn1 zip(Fn2 appFn) { /** * {@inheritDoc} + * * @param lazyAppFn */ @Override @@ -180,6 +188,27 @@ default Fn1> carry() { return (Fn1>) Cartesian.super.carry(); } + /** + * Choose between either applying this function or returning back a different result altogether. + * + * @param the potentially different result + * @return teh strengthened {@link Fn1} + */ + @Override + default Fn1, Choice2> cocartesian() { + return a -> a.fmap(this); + } + + /** + * Choose between a successful result b or returning back the input, a. + * + * @return an {@link Fn1} that chooses between its input (in case of failure) or its output. + */ + @Override + default Fn1> choose() { + return a -> Either.trying(() -> apply(a), constantly(a)).match(Choice2::a, Choice2::b); + } + @Override default Fn1 contraMap(Function fn) { return (Fn1) Cartesian.super.contraMap(fn); diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java index 71f3afb5c..97ef582b0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java @@ -5,15 +5,16 @@ import java.util.function.Function; /** - * {@link Profunctor} strength in the cartesian sense: p a b -> p (c, a) (c, b) for any type + * {@link Profunctor} strength in the cartesian product sense: p a b -> p (c ^ a) (c ^ b) for any type * c. * * @param the type of the left parameter * @param the type of the left parameter - * @param the unification parameter + * @param

the unification parameter * @see com.jnape.palatable.lambda.functions.Fn1 + * @see Cocartesian */ -public interface Cartesian> extends Profunctor { +public interface Cartesian> extends Profunctor { /** * Pair some type C to this profunctor's carrier types. @@ -21,7 +22,7 @@ public interface Cartesian> extends Profuncto * @param the paired type * @return the cartesian-strengthened profunctor */ - Cartesian, Tuple2, S> cartesian(); + Cartesian, Tuple2, P> cartesian(); /** * Pair the covariantly-positioned carrier type with the contravariantly-positioned carrier type. This can be @@ -29,25 +30,25 @@ public interface Cartesian> extends Profuncto * * @return the profunctor with the first parameter carried */ - default Cartesian, S> carry() { + default Cartesian, P> carry() { return this.cartesian().contraMap(Tuple2::fill); } @Override - Cartesian diMap(Function lFn, Function rFn); + Cartesian diMap(Function lFn, Function rFn); @Override - default Cartesian diMapL(Function fn) { - return (Cartesian) Profunctor.super.diMapL(fn); + default Cartesian diMapL(Function fn) { + return (Cartesian) Profunctor.super.diMapL(fn); } @Override - default Cartesian diMapR(Function fn) { - return (Cartesian) Profunctor.super.diMapR(fn); + default Cartesian diMapR(Function fn) { + return (Cartesian) Profunctor.super.diMapR(fn); } @Override - default Cartesian contraMap(Function fn) { - return (Cartesian) Profunctor.super.contraMap(fn); + default Cartesian contraMap(Function fn) { + return (Cartesian) Profunctor.super.contraMap(fn); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java b/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java new file mode 100644 index 000000000..8d76e9c45 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java @@ -0,0 +1,66 @@ +package com.jnape.palatable.lambda.functor; + +import com.jnape.palatable.lambda.adt.choice.Choice2; + +import java.util.function.Function; + +/** + * {@link Profunctor} strength in the cocartesian coproduct sense: p a b -> p (c v a) (c v b) for any + * type c. + * + * @param the type of the left parameter + * @param the type of the left parameter + * @param

the unification parameter + * @see com.jnape.palatable.lambda.functions.Fn1 + * @see Cartesian + */ +public interface Cocartesian> extends Profunctor { + + /** + * Choose some type C or this profunctor's carrier types. + * + * @param the choice type + * @return the cocartesian-costrengthened profunctor + */ + Cocartesian, Choice2, P> cocartesian(); + + /** + * Choose between the covariantly-positioned carrier type and the contravariantly-positioned carrier type. This can + * be used to encode partial functions a -> (⊥ v b) as total functions a -> (a v b). + * + * @return the profunctor with a choice + */ + default Cocartesian, P> choose() { + return this.cocartesian().contraMap(Choice2::b); + } + + /** + * {@inheritDoc} + */ + @Override + Cocartesian diMap(Function lFn, Function rFn); + + /** + * {@inheritDoc} + */ + @Override + default Cocartesian diMapL(Function fn) { + return (Cocartesian) Profunctor.super.diMapL(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Cocartesian diMapR(Function fn) { + return (Cocartesian) Profunctor.super.diMapR(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Cocartesian contraMap(Function fn) { + return (Cocartesian) Profunctor.super.contraMap(fn); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java index 865f2e2d5..41a4ec8ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java @@ -59,6 +59,9 @@ default Profunctor diMapR(Function fn) { return diMap(id(), fn); } + /** + * {@inheritDoc} + */ @Override default Profunctor contraMap(Function fn) { return diMapL(fn); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index 80af42dc1..a61b5b752 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -12,6 +12,8 @@ import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.choice.Choice2.a; +import static com.jnape.palatable.lambda.adt.choice.Choice2.b; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.Fn1.fn1; import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; @@ -54,7 +56,7 @@ public void widen() { } @Test - public void strengthen() { + public void cartesian() { Fn1 add1 = x -> x + 1; assertEquals(tuple("a", 2), add1.cartesian().apply(tuple("a", 1))); } @@ -64,4 +66,18 @@ public void carry() { Fn1 add1 = x -> x + 1; assertEquals(tuple(1, 2), add1.carry().apply(1)); } + + @Test + public void cocartesian() { + Fn1 add1 = x -> x + 1; + assertEquals(a("foo"), add1.cocartesian().apply(a("foo"))); + assertEquals(b(2), add1.cocartesian().apply(b(1))); + } + + @Test + public void choose() { + Fn1 add1 = Integer::parseInt; + assertEquals(b(123), add1.choose().apply("123")); + assertEquals(a("foo"), add1.choose().apply("foo")); + } } From 68206c0796571c30f0ccca34c08020fb36b83789 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 21 Apr 2019 15:54:32 -0500 Subject: [PATCH 131/348] Adding Optic, a generic supertype for profunctor optics --- CHANGELOG.md | 1 + .../jnape/palatable/lambda/optics/Optic.java | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/Optic.java diff --git a/CHANGELOG.md b/CHANGELOG.md index faf352044..ab9f8bb10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ might need to be reworked, and subtyping is obviously no longer supported. - `IO#unsafePerformAsyncIO` overloads for running `IO`s asynchronously - `IO`s automatically encode parallelism in composition - `IO#exceptionally` for recovering from failure during `IO` operation +- `Optic`, a generic supertype for all profunctor optics ### Fixed - issue where certain ways to compose `Effect`s unintentionally nullified the effect diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java new file mode 100644 index 000000000..684305785 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java @@ -0,0 +1,45 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; + +/** + * A generic supertype representation for profunctor optics. + *

+ * Precisely stated, for some {@link Profunctor} P and some {@link Functor} F, and for the + * types S T A B, an + * {@link Optic}<P, F, S, T, A, B> is a polymorphic function + * (P<A, F<B>> -> P<S, F<T>>) (existentially-quantified allowing for + * covariance). + * + * @param

the {@link Profunctor} type + * @param the {@link Functor} type + * @param the left side of the output profunctor + * @param the right side's functor embedding of the output profunctor + * @param the left side of the input profunctor + * @param the right side's functor embedding of the input profunctor + */ +@FunctionalInterface +public interface Optic

, F extends Functor, S, T, A, B> { + + , ? extends CoP>, + PSFT extends Profunctor, ? extends CoP>> PSFT apply(PAFB pafb); + + /** + * Produce a monomorphic {@link Fn1} backed by this {@link Optic}. + * + * @param the covariant bound on P + * @param the covariant bound on F + * @param the fixed input profunctor type + * @param the fixed output profunctor type + * @return the monomorphic {@link Fn1} backed by this {@link Optic} + */ + default , ? extends CoP>, + PSFT extends Profunctor, ? extends CoP>> + Fn1 monomorphize() { + return Optic.this::apply; + } +} From b643ba836c5916d1d8193822e5efb4e7b40c489a Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 21 Apr 2019 18:53:09 -0500 Subject: [PATCH 132/348] Lens and Iso are now Optics; retargeting new optic interface for everything --- CHANGELOG.md | 2 + .../jnape/palatable/lambda/adt/hmap/HMap.java | 2 +- .../palatable/lambda/adt/hmap/Schema.java | 21 +- .../lambda/adt/hmap/TypeSafeKey.java | 31 +-- .../palatable/lambda/functor/Profunctor.java | 3 +- .../lambda/functor/builtin/Exchange.java | 1 - .../jnape/palatable/lambda/lens/LensLike.java | 161 -------------- .../lambda/lens/functions/Under.java | 52 ----- .../lambda/{lens => optics}/Iso.java | 153 +++++-------- .../lambda/{lens => optics}/Lens.java | 100 +++++---- .../jnape/palatable/lambda/optics/Optic.java | 208 +++++++++++++++++- .../{lens => optics}/functions/Over.java | 30 +-- .../{lens => optics}/functions/Set.java | 24 +- .../lambda/optics/functions/Under.java | 60 +++++ .../{lens => optics}/functions/View.java | 21 +- .../lenses/CollectionLens.java | 6 +- .../{lens => optics}/lenses/EitherLens.java | 6 +- .../{lens => optics}/lenses/HListLens.java | 6 +- .../{lens => optics}/lenses/HMapLens.java | 6 +- .../{lens => optics}/lenses/IterableLens.java | 12 +- .../{lens => optics}/lenses/ListLens.java | 13 +- .../{lens => optics}/lenses/MapLens.java | 20 +- .../{lens => optics}/lenses/MaybeLens.java | 6 +- .../{lens => optics}/lenses/SetLens.java | 6 +- .../palatable/lambda/adt/hmap/HMapTest.java | 2 +- .../palatable/lambda/adt/hmap/SchemaTest.java | 2 +- .../lambda/adt/hmap/TypeSafeKeyTest.java | 2 +- .../lambda/{lens => optics}/IsoTest.java | 18 +- .../lambda/{lens => optics}/LensTest.java | 36 +-- .../{lens => optics}/functions/OverTest.java | 8 +- .../{lens => optics}/functions/SetTest.java | 8 +- .../{lens => optics}/functions/UnderTest.java | 8 +- .../{lens => optics}/functions/ViewTest.java | 8 +- .../lenses/CollectionLensTest.java | 12 +- .../lenses/EitherLensTest.java | 8 +- .../lenses/HListLensTest.java | 4 +- .../{lens => optics}/lenses/HMapLensTest.java | 2 +- .../lenses/IterableLensTest.java | 14 +- .../{lens => optics}/lenses/ListLensTest.java | 12 +- .../{lens => optics}/lenses/MapLensTest.java | 14 +- .../lenses/MaybeLensTest.java | 18 +- .../{lens => optics}/lenses/SetLensTest.java | 4 +- .../testsupport/assertion/LensAssert.java | 13 +- .../testsupport/matchers/LensMatcher.java | 59 ----- 44 files changed, 588 insertions(+), 614 deletions(-) delete mode 100644 src/main/java/com/jnape/palatable/lambda/lens/LensLike.java delete mode 100644 src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/Iso.java (60%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/Lens.java (73%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/functions/Over.java (51%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/functions/Set.java (57%) create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/functions/View.java (52%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/lenses/CollectionLens.java (94%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/lenses/EitherLens.java (91%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/lenses/HListLens.java (90%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/lenses/HMapLens.java (81%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/lenses/IterableLens.java (86%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/lenses/ListLens.java (88%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/lenses/MapLens.java (93%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/lenses/MaybeLens.java (97%) rename src/main/java/com/jnape/palatable/lambda/{lens => optics}/lenses/SetLens.java (91%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/IsoTest.java (72%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/LensTest.java (72%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/functions/OverTest.java (68%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/functions/SetTest.java (67%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/functions/UnderTest.java (68%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/functions/ViewTest.java (67%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/lenses/CollectionLensTest.java (80%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/lenses/EitherLensTest.java (86%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/lenses/HListLensTest.java (90%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/lenses/HMapLensTest.java (96%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/lenses/IterableLensTest.java (87%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/lenses/ListLensTest.java (79%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/lenses/MapLensTest.java (94%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/lenses/MaybeLensTest.java (80%) rename src/test/java/com/jnape/palatable/lambda/{lens => optics}/lenses/SetLensTest.java (92%) delete mode 100644 src/test/java/testsupport/matchers/LensMatcher.java diff --git a/CHANGELOG.md b/CHANGELOG.md index ab9f8bb10..1263a8cf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ might need to be reworked, and subtyping is obviously no longer supported. - ***Breaking Change***: Eliminated all raw types and java11 warnings. This required using capture in unification parameters for Functor and friends, so nearly every functor's type-signature changed. - ***Breaking Change***: `Strong` is now called `Cartesian` to better reflect the type of strength +- ***Breaking Change***: new Optic type hierarchy more faithfully encodes profunctor constraints on optics, new `Optic` + type is now the supertype of `Lens` and `Iso`, and `lens` package has been moved to `optics` - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ### Added 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 19a166bc1..e1677d49f 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 @@ -17,7 +17,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.maybe; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Collections.emptyMap; /** 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 index 6a57cbbbd..f72b9f8b4 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java @@ -11,14 +11,14 @@ 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.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Both; import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.lens.Lens; - -import java.util.function.Function; +import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.optics.Lens; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; -import static com.jnape.palatable.lambda.lens.lenses.HMapLens.valueAt; +import static com.jnape.palatable.lambda.optics.lenses.HMapLens.valueAt; /** * A lens that focuses on the {@link HList heterogeneous list} of values pointed at by one or more @@ -39,9 +39,9 @@ default > Schema add(TypeSafeKe maybeNewValues -> maybeNewValues.fmap(HCons::head))); return new Schema() { @Override - public , FT extends Functor, FB extends Functor, F>> - FT apply(Function, ? extends FB> fn, HMap hmap) { - return lens.apply(fn, hmap); + public >, CoF extends Functor>, FB extends Functor, ? extends CoF>, FT extends Functor, PAFB extends Profunctor, FB, ? extends CoP>, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { + return lens.apply(pafb); } }; } @@ -52,10 +52,9 @@ static Schema> schema(TypeSafeKey key) { .mapB(maybeSingletonA -> maybeSingletonA.fmap(HCons::head)); return new Schema>() { @Override - public , FT extends Functor, - FB extends Functor>, F>> FT apply( - Function>, ? extends FB> fn, HMap hmap) { - return lens.apply(fn, hmap); + public >, CoF extends Functor>, FB extends Functor>, ? extends CoF>, FT extends Functor, PAFB extends Profunctor>, FB, ? extends CoP>, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { + return lens.apply(pafb); } }; } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java index 2ee0c6622..ce9361693 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java @@ -3,8 +3,8 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.LensLike; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Optic; import java.util.Objects; @@ -23,14 +23,14 @@ */ public interface TypeSafeKey extends Iso.Simple { + @Override - default TypeSafeKey discardR(Applicative>> appB) { + default TypeSafeKey discardR(Applicative> appB) { Iso.Simple discarded = Iso.Simple.super.discardR(appB); return new TypeSafeKey() { @Override - public

, F extends Functor, FB extends Functor, - FT extends Functor, PAFB extends Profunctor, - PSFT extends Profunctor> PSFT apply(PAFB pafb) { + public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { return discarded.apply(pafb); } @@ -49,7 +49,7 @@ public boolean equals(Object obj) { /** * Left-to-right composition of this {@link TypeSafeKey} with some other {@link Iso}. Because the first parameter * fundamentally represents an already stored value type, this is the only composition that is possible for - * {@link TypeSafeKey}, which is why only this (and not {@link Iso#compose(Iso)}) is overridden. + * {@link TypeSafeKey}, which is why only this (and not {@link Iso#compose(Optic)}) is overridden. *

* Particularly of note is the fact that values stored at this key are still stored as their original manifest * type, and are not duplicated - which is to say, putting a value at a key, yielding a new key via composition, @@ -61,13 +61,12 @@ public boolean equals(Object obj) { * @return the new {@link TypeSafeKey} */ @Override - default TypeSafeKey andThen(Iso.Simple f) { + default TypeSafeKeyandThen(Iso.Simple f) { Iso.Simple composed = Iso.Simple.super.andThen(f); return new TypeSafeKey() { @Override - public

, F extends Functor, FB extends Functor, - FT extends Functor, PAFB extends Profunctor, - PSFT extends Profunctor> PSFT apply(PAFB pafb) { + public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { return composed.apply(pafb); } @@ -112,9 +111,13 @@ interface Simple extends TypeSafeKey { @Override @SuppressWarnings("unchecked") - default

, F extends Functor, FB extends Functor, - FT extends Functor, PAFB extends Profunctor, - PSFT extends Profunctor> PSFT apply(PAFB pafb) { + default >, + CoF extends Functor>, + FB extends Functor, + FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply( + PAFB pafb) { return (PSFT) pafb; } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java index 41a4ec8ae..2c4b45200 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java @@ -1,7 +1,6 @@ package com.jnape.palatable.lambda.functor; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.lens.Lens; import java.util.function.Function; @@ -19,7 +18,7 @@ * @see Bifunctor * @see Contravariant * @see Fn1 - * @see Lens + * @see com.jnape.palatable.lambda.optics.Optic */ @FunctionalInterface public interface Profunctor> extends Contravariant> { diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java index 6a317784c..d997eaf5d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java @@ -1,7 +1,6 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.lens.Iso; import java.util.function.Function; diff --git a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java b/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java deleted file mode 100644 index d0c4647f1..000000000 --- a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.jnape.palatable.lambda.lens; - -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.Profunctor; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -/** - * The generic supertype of all types that can be treated as lenses but should preserve type-specific return types in - * overrides. This type only exists to appease Java's unfortunate parametric type hierarchy constraints. If you're here, - * you're probably looking for {@link Lens} or {@link Iso}. - * - * @param the type of the "larger" value for reading - * @param the type of the "larger" value for putting - * @param the type of the "smaller" value that is read - * @param the type of the "smaller" update value - * @param the concrete lens subtype - * @see Lens - * @see Iso - */ -public interface LensLike> extends - Monad>, - Profunctor> { - - , FT extends Functor, FB extends Functor> FT apply( - Function fn, S s); - - /** - * Right-to-left composition of lenses. Requires compatibility between A and B. - * - * @param g the other lens - * @param the new "larger" value for reading (previously S) - * @param the new "larger" value for putting (previously T) - * @return the composed lens - */ - LensLike compose(LensLike g); - - /** - * Left-to-right composition of lenses. Requires compatibility between S and T. - * - * @param f the other lens - * @param the new "smaller" value to read (previously A) - * @param the new "smaller" update value (previously B) - * @return the composed lens - */ - LensLike andThen(LensLike f); - - /** - * Contravariantly map S to R, yielding a new lens. - * - * @param fn the mapping function - * @param the type of the new "larger" value for reading - * @return the new lens - */ - LensLike mapS(Function fn); - - /** - * Covariantly map T to U, yielding a new lens. - * - * @param fn the mapping function - * @param the type of the new "larger" value for putting - * @return the new lens - */ - LensLike mapT(Function fn); - - /** - * Covariantly map A to C, yielding a new lens. - * - * @param fn the mapping function - * @param the type of the new "smaller" value that is read - * @return the new lens - */ - LensLike mapA(Function fn); - - /** - * Contravariantly map B to Z, yielding a new lens. - * - * @param fn the mapping function - * @param the type of the new "smaller" update value - * @return the new lens - */ - LensLike mapB(Function fn); - - @Override - LensLike flatMap(Function>> f); - - @Override - LensLike pure(U u); - - @Override - default LensLike fmap(Function fn) { - return Monad.super.fmap(fn).coerce(); - } - - @Override - default LensLike zip( - Applicative, LensLike> appFn) { - return Monad.super.zip(appFn).coerce(); - } - - @Override - default LensLike discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); - } - - @Override - default LensLike discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); - } - - @Override - default LensLike diMapL(Function fn) { - return (LensLike) Profunctor.super.diMapL(fn); - } - - @Override - default LensLike diMapR(Function fn) { - return (LensLike) Profunctor.super.diMapR(fn); - } - - @Override - default LensLike diMap(Function lFn, - Function rFn) { - return this.mapS(lFn).mapT(rFn); - } - - @Override - default LensLike contraMap(Function fn) { - return (LensLike) Profunctor.super.contraMap(fn); - } - - /** - * A simpler type signature for lenses where S/T and A/B are equivalent. - * - * @param the "larger" type - * @param the "smaller" type - * @param the concrete lens subtype - */ - interface Simple> extends LensLike { - - /** - * Compose two simple lenses from right to left. - * - * @param g the other simple lens - * @param the other simple lens' larger type - * @return the composed simple lens - */ - LensLike.Simple compose(LensLike.Simple g); - - /** - * Compose two simple lenses from left to right. - * - * @param f the other simple lens - * @param the other simple lens' smaller type - * @return the composed simple lens - */ - LensLike.Simple andThen(LensLike.Simple f); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java b/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java deleted file mode 100644 index 1bdae90bf..000000000 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/Under.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.jnape.palatable.lambda.lens.functions; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functions.Fn3; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.LensLike; - -import java.util.function.Function; - -/** - * The inverse of {@link Over}: given an {@link Iso}, a function from T to S, and a "smaller" - * value B, return a "smaller" value A by traversing around the type ring (B -> T - * -> S -> A). - *

- * Note this is only possible for {@link Iso}s and not general {@link LensLike}s because of the mandatory need for the - * correspondence B -> T. - * - * @param the larger type for focusing - * @param the larger type for mirrored focusing - * @param the smaller type for focusing - * @param the smaller type for mirrored focusing - */ -public final class Under implements Fn3, Function, B, A> { - - private static final Under INSTANCE = new Under<>(); - - private Under() { - } - - @Override - public A apply(Iso iso, Function fn, B b) { - return iso.unIso().into((sa, bt) -> bt.fmap(fn).fmap(sa)).apply(b); - } - - @SuppressWarnings("unchecked") - public static Under under() { - return (Under) INSTANCE; - } - - public static Fn2, B, A> under(Iso iso) { - return Under.under().apply(iso); - } - - public static Fn1 under(Iso iso, Function fn) { - return under(iso).apply(fn); - } - - public static A under(Iso iso, Function fn, B b) { - return under(iso, fn).apply(b); - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java similarity index 60% rename from src/main/java/com/jnape/palatable/lambda/lens/Iso.java rename to src/main/java/com/jnape/palatable/lambda/optics/Iso.java index bc3e76389..e84ecb048 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.lens; +package com.jnape.palatable.lambda.optics; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; @@ -8,21 +8,23 @@ import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.functor.builtin.Exchange; import com.jnape.palatable.lambda.functor.builtin.Identity; -import com.jnape.palatable.lambda.lens.functions.Over; -import com.jnape.palatable.lambda.lens.functions.Set; -import com.jnape.palatable.lambda.lens.functions.View; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.optics.functions.Over; +import com.jnape.palatable.lambda.optics.functions.Set; +import com.jnape.palatable.lambda.optics.functions.View; import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn1.fn1; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static com.jnape.palatable.lambda.lens.Iso.Simple.adapt; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Iso.Simple.adapt; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.Optic.optic; +import static com.jnape.palatable.lambda.optics.functions.View.view; /** - * An {@link Iso} (short for "isomorphism") is an invertible {@link Lens}: a {@link LensLike} encoding of a + * An {@link Iso} (short for "isomorphism") is an invertible {@link Lens}: an {@link Optic} encoding of a * bi-directional focusing of two types, and like {@link Lens}es, can be {@link View}ed, * {@link Set}, and {@link Over}ed. *

@@ -50,17 +52,10 @@ * @param the smaller type for mirrored focusing */ @FunctionalInterface -public interface Iso extends LensLike> { - -

, F extends Functor, FB extends Functor, FT extends Functor, - PAFB extends Profunctor, - PSFT extends Profunctor> PSFT apply(PAFB pafb); - - @Override - default , FT extends Functor, FB extends Functor> FT apply( - Function fn, S s) { - return this., F, FB, FT, Fn1, Fn1>apply(fn1(fn)).apply(s); - } +public interface Iso extends + Optic, Functor, S, T, A, B>, + Monad>, + Profunctor> { /** * Convert this {@link Iso} into a {@link Lens}. @@ -68,13 +63,7 @@ default , FT extends Functor, FB extends Functor toLens() { - return new Lens() { - @Override - public , FT extends Functor, FB extends Functor> FT apply( - Function fn, S s) { - return Iso.this.apply(fn, s); - } - }; + return lens(this); } /** @@ -93,7 +82,9 @@ default Iso mirror() { * @return the destructured iso */ default Tuple2, Fn1> unIso() { - return Tuple2.fill(this., Identity, Identity, Identity, + return Tuple2.fill(this., Identity, + Identity, + Identity, Exchange>, Exchange>>apply(new Exchange<>(id(), Identity::new)).diMapR(Identity::runIdentity)) .biMap(e -> fn1(e.sa()), e -> fn1(e.bt())); @@ -101,7 +92,7 @@ default Iso mirror() { @Override default Iso fmap(Function fn) { - return LensLike.super.fmap(fn).coerce(); + return Monad.super.fmap(fn).coerce(); } @Override @@ -110,27 +101,23 @@ default Iso pure(U u) { } @Override - default Iso zip( - Applicative, LensLike>> appFn) { - return LensLike.super.zip(appFn).coerce(); + default Iso zip(Applicative, Iso> appFn) { + return Monad.super.zip(appFn).coerce(); } @Override - default Iso discardL(Applicative>> appB) { - return LensLike.super.discardL(appB).coerce(); + default Iso discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); } @Override - default Iso discardR(Applicative>> appB) { - return LensLike.super.discardR(appB).coerce(); + default Iso discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); } @Override - @SuppressWarnings("RedundantTypeArguments") - default Iso flatMap( - Function>>> fn) { - return unIso().fmap(bt -> Fn2.fn2(fn1(bt.andThen( - fn.>andThen(Monad>>::coerce)) + default Iso flatMap(Function>> fn) { + return unIso().fmap(bt -> Fn2.fn2(fn1(bt.andThen(fn.>andThen(Applicative::coerce)) .andThen(Iso::unIso) .andThen(Tuple2::_2) .andThen(Fn1::fn1)))) @@ -141,77 +128,53 @@ default Iso flatMap( @Override default Iso diMapL(Function fn) { - return LensLike.super.diMapL(fn).coerce(); + return (Iso) Profunctor.super.diMapL(fn); } @Override default Iso diMapR(Function fn) { - return LensLike.super.diMapR(fn).coerce(); + return (Iso) Profunctor.super.diMapR(fn); } @Override default Iso diMap(Function lFn, Function rFn) { - return LensLike.super.diMap(lFn, rFn).coerce(); + return this.mapS(lFn).mapT(rFn); } @Override default Iso contraMap(Function fn) { - return LensLike.super.contraMap(fn).coerce(); + return (Iso) Profunctor.super.contraMap(fn); } @Override default Iso mapS(Function fn) { - return unIso().biMapL(f -> f.compose(fn)).into(Iso::iso); + return iso(Optic.super.mapS(fn)); } @Override default Iso mapT(Function fn) { - return unIso().biMapR(f -> f.andThen(fn)).into(Iso::iso); + return iso(Optic.super.mapT(fn)); } @Override default Iso mapA(Function fn) { - return unIso().biMapL(f -> f.andThen(fn)).into(Iso::iso); + return iso(Optic.super.mapA(fn)); } @Override default Iso mapB(Function fn) { - return unIso().biMapR(f -> f.compose(fn)).into(Iso::iso); + return iso(Optic.super.mapB(fn)); } @Override - default Lens andThen(LensLike f) { - return toLens().andThen(f); - } - - /** - * Left-to-right composition of {@link Iso}. - * - * @param f the iso to apply after this one - * @param the smaller type the first larger type can be viewed as - * @param the smaller type that can be viewed as the second larger type - * @return the composed {@link Iso} - */ - default Iso andThen(Iso f) { - return unIso().into((sa, bt) -> f.unIso().into((ac, db) -> iso(sa.andThen(ac), db.andThen(bt)))); - } - - /** - * Right-to-left composition of {@link Iso}. - * - * @param g the iso to apply before this one - * @param the larger type that can be viewed as the first smaller type - * @param the larger type the second smaller type can be viewed as - * @return the composed {@link Iso} - */ - default Iso compose(Iso g) { - return g.andThen(this); + default Iso andThen(Optic, ? super Functor, A, B, Z, C> f) { + return iso(Optic.super.andThen(f)); } @Override - default Lens compose(LensLike f) { - return toLens().compose(f); + default Iso compose(Optic, ? super Functor, R, U, S, T> g) { + return iso(Optic.super.compose(g)); } /** @@ -227,13 +190,16 @@ default Lens compose(LensLike f) { */ static Iso iso(Function f, Function g) { + return iso(optic(pafb -> pafb.diMap(f, fb -> fb.fmap(g)))); + } + + static Iso iso( + Optic, ? super Functor, S, T, A, B> optic) { return new Iso() { @Override - @SuppressWarnings("unchecked") - public

, F extends Functor, FB extends Functor, - FT extends Functor, PAFB extends Profunctor, - PSFT extends Profunctor> PSFT apply(PAFB pafb) { - return (PSFT) pafb.diMap(f, fb -> (FT) fb.fmap(g)); + public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { + return optic.apply(pafb); } }; } @@ -259,7 +225,7 @@ static Iso.Simple simpleIso(Function f, Fun * @param the type of both "smaller" values */ @FunctionalInterface - interface Simple extends Iso, LensLike.Simple> { + interface Simple extends Iso, Optic.Simple, Functor, S, A> { /** * Compose two simple isos from right to left. @@ -296,34 +262,35 @@ default Lens.Simple toLens() { } @Override - default Iso.Simple discardR(Applicative>> appB) { + default Iso.Simple discardR(Applicative> appB) { return adapt(Iso.super.discardR(appB)); } @Override - default Lens.Simple compose(LensLike.Simple g) { - return toLens().compose(g); + default Iso.Simple andThen(Optic.Simple, ? super Functor, A, B> f) { + return adapt(Iso.super.andThen(f)); } @Override - default Lens.Simple andThen(LensLike.Simple f) { - return toLens().andThen(f); + default Iso.Simple compose(Optic.Simple, ? super Functor, R, S> g) { + return adapt(Iso.super.compose(g)); } /** - * Adapt an {@link Iso} with the right variance to an {@link Iso.Simple}. + * Adapt an {@link Optic} with the right variance to an {@link Iso.Simple}. * - * @param iso the iso - * @param S/T - * @param A/B + * @param optic the optic + * @param S/T + * @param A/B * @return the simple iso */ - static Iso.Simple adapt(Iso iso) { + static Iso.Simple adapt( + Optic, ? super Functor, S, S, A, A> optic) { return new Iso.Simple() { @Override - public

, F extends Functor, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( + public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( PAFB pafb) { - return iso.apply(pafb); + return optic.apply(pafb); } }; } diff --git a/src/main/java/com/jnape/palatable/lambda/lens/Lens.java b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java similarity index 73% rename from src/main/java/com/jnape/palatable/lambda/lens/Lens.java rename to src/main/java/com/jnape/palatable/lambda/optics/Lens.java index edcb93650..c39feabd3 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java @@ -1,20 +1,20 @@ -package com.jnape.palatable.lambda.lens; +package com.jnape.palatable.lambda.optics; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Both; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.monad.Monad; 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; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.Lens.Simple.adapt; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; /** * An approximation of van Laarhoven lenses. @@ -137,11 +137,14 @@ * @param the type of the "smaller" update value */ @FunctionalInterface -public interface Lens extends LensLike> { +public interface Lens extends + Optic, Functor, S, T, A, B>, + Monad>, + Profunctor> { @Override default Lens fmap(Function fn) { - return LensLike.super.fmap(fn).coerce(); + return Monad.super.fmap(fn).coerce(); } @Override @@ -150,66 +153,65 @@ default Lens pure(U u) { } @Override - default Lens zip( - Applicative, LensLike>> appFn) { - return LensLike.super.zip(appFn).coerce(); + default Lens zip(Applicative, Lens> appFn) { + return Monad.super.zip(appFn).coerce(); } @Override - default Lens discardL(Applicative>> appB) { - return LensLike.super.discardL(appB).coerce(); + default Lens discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); } @Override - default Lens discardR(Applicative>> appB) { - return LensLike.super.discardR(appB).coerce(); + default Lens discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); } @Override - default Lens flatMap( - Function>>> f) { + default Lens flatMap(Function>> f) { + return lens(view(this), (s, b) -> set(f.apply(set(this, b, s)).>coerce(), b, s)); } @Override default Lens diMapL(Function fn) { - return LensLike.super.diMapL(fn).coerce(); + return (Lens) Profunctor.super.diMapL(fn); } @Override default Lens diMapR(Function fn) { - return LensLike.super.diMapR(fn).coerce(); + return (Lens) Profunctor.super.diMapR(fn); } @Override default Lens diMap(Function lFn, Function rFn) { - return LensLike.super.diMap(lFn, rFn).coerce(); + return this.mapS(lFn).mapT(rFn); } @Override default Lens contraMap(Function fn) { - return LensLike.super.contraMap(fn).coerce(); + return (Lens) Profunctor.super.contraMap(fn); } @Override default Lens mapS(Function fn) { - return lens(view(this).compose(fn), (r, b) -> set(this, b, fn.apply(r))); + return lens(Optic.super.mapS(fn)); } @Override default Lens mapT(Function fn) { - return fmap(fn); + return lens(Optic.super.mapT(fn)); } @Override default Lens mapA(Function fn) { - return andThen(lens(fn, (a, b) -> b)); + return lens(Optic.super.mapA(fn)); } @Override default Lens mapB(Function fn) { - return lens(view(this), (s, z) -> set(this, fn.apply(z), s)); + return lens(Optic.super.mapB(fn)); } /** @@ -223,13 +225,13 @@ default Iso toIso(S s) { } @Override - default Lens andThen(LensLike f) { - return lens(view(this).fmap(view(f)), (q, b) -> over(this, set(f, b), q)); + default Lens andThen(Optic, ? super Functor, A, B, C, D> f) { + return lens(Optic.super.andThen(f)); } @Override - default Lens compose(LensLike g) { - return lens(view(g).fmap(view(this)), (q, b) -> over(g, set(this, b), q)); + default Lens compose(Optic, ? super Functor, R, U, S, T> g) { + return lens(Optic.super.compose(g)); } /** @@ -245,13 +247,21 @@ default Lens compose(LensLike g) { */ static Lens lens(Function getter, BiFunction setter) { + return lens(Optic., Functor, + S, T, A, B, + Functor>, + Functor>, + Fn1>>, + Fn1>>>optic(afb -> s -> afb.apply(getter.apply(s)) + .fmap(b -> setter.apply(s, b)))); + } + + static Lens lens(Optic, ? super Functor, S, T, A, B> optic) { return new Lens() { @Override - @SuppressWarnings("unchecked") - public , FT extends Functor, FB extends Functor> FT apply( - Function fn, - S s) { - return (FT) fn.apply(getter.apply(s)).fmap(b -> setter.apply(s, b)); + public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( + PAFB pafb) { + return optic.apply(pafb); } }; } @@ -309,14 +319,16 @@ static Lens.Simple> both(Lens.Simple f, Lens.Sim * @param the type of both "smaller" values */ @FunctionalInterface - interface Simple extends Lens, LensLike.Simple> { + interface Simple extends Lens, Optic.Simple, Functor, S, A> { - default Lens.Simple compose(LensLike.Simple g) { - return Lens.Simple.adapt(Lens.super.compose(g)); + @Override + default Lens.Simple andThen(Optic.Simple, ? super Functor, A, B> f) { + return Lens.Simple.adapt(Lens.super.andThen(f)); } - default Lens.Simple andThen(LensLike.Simple f) { - return Lens.Simple.adapt(Lens.super.andThen(f)); + @Override + default Lens.Simple compose(Optic.Simple, ? super Functor, R, S> g) { + return Lens.Simple.adapt(Lens.super.compose(g)); } /** @@ -327,12 +339,14 @@ default Lens.Simple andThen(LensLike.Simple f) { * @param A/B * @return the simple lens */ - static Lens.Simple adapt(Lens lens) { + static Lens.Simple adapt(Optic, ? super Functor, S, S, A, A> lens) { return new Lens.Simple() { @Override - public , FT extends Functor, FB extends Functor> FT apply( - Function fn, S s) { - return lens.apply(fn, s); + public >, + CoF extends Functor>, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return lens.apply(pafb); } }; } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java index 684305785..c53e200e5 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java @@ -4,6 +4,8 @@ import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; +import java.util.function.Function; + /** * A generic supertype representation for profunctor optics. *

@@ -21,11 +23,14 @@ * @param the right side's functor embedding of the input profunctor */ @FunctionalInterface -public interface Optic

, F extends Functor, S, T, A, B> { +public interface Optic

, F extends Functor, S, T, A, B> { - , ? extends CoP>, - PSFT extends Profunctor, ? extends CoP>> PSFT apply(PAFB pafb); + , + CoF extends Functor, + FB extends Functor, + FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb); /** * Produce a monomorphic {@link Fn1} backed by this {@link Optic}. @@ -36,10 +41,197 @@ public interface Optic

, F extends Functor, S * @param the fixed output profunctor type * @return the monomorphic {@link Fn1} backed by this {@link Optic} */ - default , ? extends CoP>, - PSFT extends Profunctor, ? extends CoP>> + default , + CoF extends Functor, + FB extends Functor, + FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> Fn1 monomorphize() { - return Optic.this::apply; + return this::apply; + } + + /** + * Left-to-right composition of optics. Requires compatibility between S> and T. + * + * @param f the other optic + * @param the new left side of the input profunctor + * @param the new right side's functor embedding of the input profunctor + * @return the composed optic + */ + default Optic andThen(Optic f) { + return new Optic() { + @Override + public , + CoF extends Functor, + FC extends Functor, + FT extends Functor, + PZFC extends Profunctor, + PSFT extends Profunctor> + PSFT apply(PZFC pzfc) { + return Optic.this.apply(f.apply(pzfc)); + } + }; + } + + /** + * Right-to-Left composition of optics. Requires compatibility between A and B. + * + * @param g the other optic + * @param the new left side of the output profunctor + * @param the new right side's functor embedding of the output profunctor + * @return the composed optic + */ + default Optic compose(Optic g) { + return new Optic() { + @Override + public , + CoF extends Functor, + FB extends Functor, + FU extends Functor, + PAFB extends Profunctor, + PRFU extends Profunctor> + PRFU apply(PAFB pafb) { + return g., FU, + Profunctor, ? extends CoP>, PRFU>apply(Optic.this.apply(pafb)); + } + }; + } + + /** + * Contravariantly map S to R, yielding a new optic. + * + * @param fn the mapping function + * @param the new left side of the output profunctor + * @return the new optic + */ + default Optic mapS(Function fn) { + return optic(pafb -> { + Profunctor, ? extends P> psft = apply(pafb); + return psft.diMapL(fn); + }); + } + + /** + * Covariantly map T to U, yielding a new optic. + * + * @param fn the mapping function + * @param the new right side's functor embedding of the output profunctor + * @return the new optic + */ + default Optic mapT(Function fn) { + return optic(pafb -> { + Profunctor, ? extends P> psft = apply(pafb); + return psft.diMapR(ft -> ft.fmap(fn)); + }); + } + + /** + * Covariantly map A to C, yielding a new optic. + * + * @param fn the mapping function + * @param the new left side of the input profunctor + * @return the new optic + */ + default Optic mapA(Function fn) { + return optic(pcfb -> { + @SuppressWarnings("UnnecessaryLocalVariable") + Profunctor, ? extends P> psft = apply(pcfb.diMapL(fn)); + return psft; + }); + } + + /** + * Contravariantly map B to Z, yielding a new optic. + * + * @param fn the mapping function + * @param the new right side's functor embedding of the input profunctor + * @return the new optic + */ + default Optic mapB(Function fn) { + return optic(pafz -> apply(pafz.diMapR(fz -> fz.fmap(fn)))); + } + + /** + * Promote a monomorphic function to a compatible {@link Optic}. + * + * @param fn the function + * @param

the {@link Profunctor} type + * @param the {@link Functor} type + * @param the left side of the output profunctor + * @param the right side's functor embedding of the output profunctor + * @param the left side of the input profunctor + * @param the right side's functor embedding of the input profunctor + * @param the input + * @param the output + * @return the {@link Optic} + */ + static

, + F extends Functor, + S, T, A, B, + FB extends Functor, + FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> Optic optic( + Function fn) { + return new Optic() { + @Override + @SuppressWarnings("unchecked") + public , + CoF extends Functor, + CoFB extends Functor, + CoFT extends Functor, + CoPAFB extends Profunctor, + CoPSFT extends Profunctor> CoPSFT apply( + CoPAFB pafb) { + return (CoPSFT) fn.apply((PAFB) pafb); + } + }; + } + + interface Simple

, F extends Functor, S, A> extends + Optic { + + /** + * Compose two simple optics from left to right. + * + * @param f the other simple optic + * @param the new left side and right side's functor embedding of the input profunctor + * @return the composed simple optic + */ + @SuppressWarnings("overloads") + default Optic.Simple andThen(Optic.Simple f) { + Optic composed = Optic.super.andThen(f); + return new Simple() { + @Override + public , CoF extends Functor, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, PSFT extends Profunctor> + PSFT apply(PAFB pafb) { + return composed.apply(pafb); + } + }; + } + + /** + * Compose two simple optics from right to left. + * + * @param g the other simple optic + * @param the new left side and right side's functor embedding of the output profunctor + * @return the composed simple optic + */ + @SuppressWarnings("overloads") + default Optic.Simple compose(Optic.Simple g) { + Optic composed = Optic.super.compose(g); + return new Simple() { + @Override + public , CoF extends Functor, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, PSFT extends Profunctor> + PSFT apply(PAFB pafb) { + return composed.apply(pafb); + } + }; + } } } diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java similarity index 51% rename from src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java rename to src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java index a0c1eaedd..de8b4a541 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/Over.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java @@ -1,10 +1,10 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functor.builtin.Identity; -import com.jnape.palatable.lambda.lens.LensLike; +import com.jnape.palatable.lambda.optics.Optic; import java.util.function.Function; @@ -23,7 +23,7 @@ * @see Set * @see View */ -public final class Over implements Fn3, Function, S, T> { +public final class Over implements Fn3, ? super Identity, S, T, A, B>, Function, S, T> { private static final Over INSTANCE = new Over<>(); @@ -31,10 +31,11 @@ private Over() { } @Override - public T apply(LensLike lens, Function fn, S s) { - return lens., Identity, Identity>apply(fn.andThen((Function>) Identity::new), - s) - .runIdentity(); + public T apply(Optic, ? super Identity, S, T, A, B> optic, + Function fn, + S s) { + return optic., Identity, Identity, Identity, Fn1>, Fn1>>apply( + a -> new Identity<>(fn.apply(a))).apply(s).runIdentity(); } @SuppressWarnings("unchecked") @@ -42,15 +43,18 @@ public static Over over() { return (Over) INSTANCE; } - public static Fn2, S, T> over(LensLike lens) { - return Over.over().apply(lens); + public static Fn2, S, T> over( + Optic, ? super Identity, S, T, A, B> optic) { + return Over.over().apply(optic); } - public static Fn1 over(LensLike lens, Function fn) { - return over(lens).apply(fn); + public static Fn1 over(Optic, ? super Identity, S, T, A, B> optic, + Function fn) { + return over(optic).apply(fn); } - public static T over(LensLike lens, Function fn, S s) { - return over(lens, fn).apply(s); + public static T over(Optic, ? super Identity, S, T, A, B> optic, + Function fn, S s) { + return over(optic, fn).apply(s); } } diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java similarity index 57% rename from src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java rename to src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java index cebf0647f..c5c7a7110 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/Set.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java @@ -1,13 +1,13 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functor.builtin.Identity; -import com.jnape.palatable.lambda.lens.LensLike; +import com.jnape.palatable.lambda.optics.Optic; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.lens.functions.Over.over; +import static com.jnape.palatable.lambda.optics.functions.Over.over; /** * Given a lens, a "smaller" value B, and a "larger" value S, produce a T by @@ -23,7 +23,7 @@ * @see Over * @see View */ -public final class Set implements Fn3, B, S, T> { +public final class Set implements Fn3, ? super Identity, S, T, A, B>, B, S, T> { private static final Set INSTANCE = new Set<>(); @@ -31,8 +31,8 @@ private Set() { } @Override - public T apply(LensLike lens, B b, S s) { - return over(lens, constantly(b), s); + public T apply(Optic, ? super Identity, S, T, A, B> optic, B b, S s) { + return over(optic, constantly(b), s); } @SuppressWarnings("unchecked") @@ -40,15 +40,15 @@ public static Set set() { return (Set) INSTANCE; } - public static Fn2 set(LensLike lens) { - return Set.set().apply(lens); + public static Fn2 set(Optic, ? super Identity, S, T, A, B> optic) { + return Set.set().apply(optic); } - public static Fn1 set(LensLike lens, B b) { - return set(lens).apply(b); + public static Fn1 set(Optic, ? super Identity, S, T, A, B> optic, B b) { + return set(optic).apply(b); } - public static T set(LensLike lens, B b, S s) { - return set(lens, b).apply(s); + public static T set(Optic, ? super Identity, S, T, A, B> optic, B b, S s) { + return set(optic, b).apply(s); } } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java new file mode 100644 index 000000000..7356d3ec1 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java @@ -0,0 +1,60 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functor.builtin.Exchange; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Optic; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; + +/** + * The inverse of {@link Over}: given an {@link Iso}, a function from T to S, and a "smaller" + * value B, return a "smaller" value A by traversing around the type ring (B -> T + * -> S -> A). + * + * @param the larger type for focusing + * @param the larger type for mirrored focusing + * @param the smaller type for focusing + * @param the smaller type for mirrored focusing + */ +public final class Under implements Fn3, ? super Identity, S, T, A, B>, Function, B, A> { + + private static final Under INSTANCE = new Under<>(); + + private Under() { + } + + @Override + public A apply(Optic, ? super Identity, S, T, A, B> optic, + Function fn, + B b) { + Exchange> exchange = optic.apply(new Exchange<>(id(), Identity::new)); + return exchange.sa().apply(fn.apply(exchange.bt().apply(b).runIdentity())); + } + + @SuppressWarnings("unchecked") + public static Under under() { + return (Under) INSTANCE; + } + + public static Fn2, B, A> under( + Optic, ? super Identity, S, T, A, B> optic) { + return Under.under().apply(optic); + } + + public static Fn1 under( + Optic, ? super Identity, S, T, A, B> optic, + Function fn) { + return under(optic).apply(fn); + } + + public static A under(Optic, ? super Identity, S, T, A, B> optic, + Function fn, B b) { + return under(optic, fn).apply(b); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/lens/functions/View.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java similarity index 52% rename from src/main/java/com/jnape/palatable/lambda/lens/functions/View.java rename to src/main/java/com/jnape/palatable/lambda/optics/functions/View.java index b4df1138d..b94992d29 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/functions/View.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java @@ -1,9 +1,9 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functor.builtin.Const; -import com.jnape.palatable.lambda.lens.LensLike; +import com.jnape.palatable.lambda.optics.Optic; /** * Given a lens and a "larger" value S, retrieve a "smaller" value A by lifting the lens into @@ -18,16 +18,17 @@ * @see Set * @see Over */ -public final class View implements Fn2, S, A> { +public final class View implements Fn2, ? super Const, S, T, A, B>, S, A> { - private static final View INSTANCE = new View<>(); + private static final View INSTANCE = new View<>(); private View() { } @Override - public A apply(LensLike lens, S s) { - return lens., Const, Const>apply(Const::new, s).runConst(); + public A apply(Optic, ? super Const, S, T, A, B> optic, S s) { + return optic., Const, Const, Const, Fn1>, Fn1>>apply( + Const::new).apply(s).runConst(); } @SuppressWarnings("unchecked") @@ -35,11 +36,11 @@ public static View view() { return (View) INSTANCE; } - public static Fn1 view(LensLike lens) { - return View.view().apply(lens); + public static Fn1 view(Optic, ? super Const, S, T, A, B> optic) { + return View.view().apply(optic); } - public static A view(LensLike lens, S s) { - return view(lens).apply(s); + public static A view(Optic, ? super Const, S, T, A, B> optic, S s) { + return view(optic).apply(s); } } diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java similarity index 94% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java index 10c54dca9..9a8a8ee29 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java @@ -1,6 +1,6 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import java.util.Collection; import java.util.HashSet; @@ -8,7 +8,7 @@ import java.util.function.Function; import java.util.stream.Stream; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link Collection}s. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/EitherLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java similarity index 91% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/EitherLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java index 50b840e5c..0aa4b86a3 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/EitherLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java @@ -1,11 +1,11 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link Either}s. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/HListLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/HListLens.java similarity index 90% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/HListLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/HListLens.java index bc0ce452b..2af87a94a 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/HListLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/HListLens.java @@ -1,12 +1,12 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.hlist.Index; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import static com.jnape.palatable.lambda.adt.hlist.HList.cons; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link HList}s. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/HMapLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/HMapLens.java similarity index 81% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/HMapLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/HMapLens.java index c7fd953da..f98446254 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/HMapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/HMapLens.java @@ -1,11 +1,11 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hmap.HMap; import com.jnape.palatable.lambda.adt.hmap.TypeSafeKey; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link HMap}s. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java similarity index 86% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java index cccf68730..3bab7f98c 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/IterableLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java @@ -1,18 +1,18 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.builtin.fn1.Head; import com.jnape.palatable.lambda.functions.builtin.fn1.Tail; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Lens; import static com.jnape.palatable.lambda.functions.Fn2.fn2; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; -import static com.jnape.palatable.lambda.lens.Iso.simpleIso; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Iso.simpleIso; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.functions.View.view; /** * Lenses that operate on {@link Iterable}s. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/ListLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/ListLens.java similarity index 88% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/ListLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/ListLens.java index b7857df2a..383c1a226 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/ListLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/ListLens.java @@ -1,7 +1,7 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import java.util.ArrayList; import java.util.List; @@ -9,9 +9,9 @@ import static com.jnape.palatable.lambda.adt.Maybe.maybe; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftA; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftB; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.unLiftA; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.unLiftB; import static java.lang.Math.abs; /** @@ -73,8 +73,7 @@ public static Lens.Simple, Maybe> elementAt(int index) { * @param the list element type * @return the element at the index, or defaultValue */ - @SuppressWarnings("unchecked") public static Lens.Simple, X> elementAt(int index, X defaultValue) { - return unLiftB(unLiftA(elementAt(index), defaultValue))::apply; + return Lens.Simple.adapt(unLiftB(unLiftA(elementAt(index), defaultValue))); } } diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java similarity index 93% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java index 63823404f..63fb09016 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java @@ -1,12 +1,12 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functions.builtin.fn2.Filter; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Lens; import java.util.ArrayList; import java.util.Collection; @@ -21,12 +21,12 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap; -import static com.jnape.palatable.lambda.lens.Lens.Simple.adapt; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftA; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.unLiftB; +import static com.jnape.palatable.lambda.optics.Lens.Simple.adapt; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.unLiftA; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.unLiftB; /** * Lenses that operate on {@link Map}s. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MaybeLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MaybeLens.java similarity index 97% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/MaybeLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/MaybeLens.java index 0917b07ae..5bb9f93da 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/MaybeLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MaybeLens.java @@ -1,9 +1,9 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link Maybe}. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java similarity index 91% rename from src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java rename to src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java index b48ceea24..a96e9eb46 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/SetLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java @@ -1,12 +1,12 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import java.util.HashSet; import java.util.Set; import java.util.function.Function; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** * Lenses that operate on {@link Set}s. 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 9c2456ab8..f9e849f78 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 @@ -13,7 +13,7 @@ import static com.jnape.palatable.lambda.adt.hmap.HMap.hMap; import static com.jnape.palatable.lambda.adt.hmap.HMap.singletonHMap; import static com.jnape.palatable.lambda.adt.hmap.TypeSafeKey.typeSafeKey; -import static com.jnape.palatable.lambda.lens.Iso.simpleIso; +import static com.jnape.palatable.lambda.optics.Iso.simpleIso; import static java.math.BigInteger.ONE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; 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 index 5d76e50cd..3fdbde74f 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java @@ -9,7 +9,7 @@ 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 com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static testsupport.assertion.LensAssert.assertLensLawfulness; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java index b9bb7e802..f03acea5b 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java @@ -6,7 +6,7 @@ import static com.jnape.palatable.lambda.adt.hmap.HMap.emptyHMap; import static com.jnape.palatable.lambda.adt.hmap.TypeSafeKey.typeSafeKey; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static com.jnape.palatable.lambda.lens.Iso.simpleIso; +import static com.jnape.palatable.lambda.optics.Iso.simpleIso; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java similarity index 72% rename from src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java index de5557f15..91c181029 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java @@ -1,8 +1,6 @@ -package com.jnape.palatable.lambda.lens; +package com.jnape.palatable.lambda.optics; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.builtin.Const; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -15,9 +13,9 @@ import java.util.List; import static com.jnape.palatable.lambda.adt.Maybe.just; -import static com.jnape.palatable.lambda.lens.Iso.iso; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; @@ -29,12 +27,8 @@ public class IsoTest { iso(Integer::parseInt, dbl -> dbl.toString().chars().mapToObj(x -> (char) x).collect(toList())); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM>, List> testSubject() { - return new EquatableM<>(ISO, iso -> { - @SuppressWarnings("UnnecessaryLocalVariable") - Functor> result = iso.apply(Const::new, "123"); - return result; - }); + public EquatableM, List> testSubject() { + return new EquatableM<>(ISO, iso -> view(iso, "123")); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java similarity index 72% rename from src/test/java/com/jnape/palatable/lambda/lens/LensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/LensTest.java index 4ab9622a9..f5b1cbf2a 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java @@ -1,7 +1,8 @@ -package com.jnape.palatable.lambda.lens; +package com.jnape.palatable.lambda.optics; import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.builtin.Const; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -19,11 +20,11 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.lens.Lens.both; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.Lens.simpleLens; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Lens.both; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.Lens.simpleLens; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.lang.Integer.parseInt; import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; @@ -41,19 +42,24 @@ public class LensTest { LENS = lens(xs -> xs.get(0), (xs, i) -> singleton(i)); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, ?, Integer, String, Lens>, ?> testSubject() { - return new EquatableM<>(lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s))), l -> view(l, emptyMap())); + public EquatableM, ?, Integer, String>, List> testSubject() { + return new EquatableM<>(lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s))), + lens -> view(lens, emptyMap())); } @Test public void setsUnderIdentity() { - Set ints = LENS., Identity>, Identity>apply(s -> new Identity<>(s.length()), asList("foo", "bar", "baz")).runIdentity(); + Set ints = LENS., Identity, Identity, Identity>, + Fn1>, Fn1, Identity>>>apply( + s -> new Identity<>(s.length())).apply(asList("foo", "bar", "baz")).runIdentity(); assertEquals(singleton(3), ints); } @Test public void viewsUnderConst() { - Integer i = LENS., Const>, Const>apply(s -> new Const<>(s.length()), asList("foo", "bar", "baz")).runConst(); + Integer i = LENS., Const, Const, Const>, + Fn1>, Fn1, Const>>>apply( + s -> new Const<>(s.length())).apply(asList("foo", "bar", "baz")).runConst(); assertEquals((Integer) 3, i); } @@ -67,10 +73,12 @@ public void mapsIndividuallyOverParameters() { .mapB((Maybe maybeI) -> maybeI.orElse(-1)); assertEquals(just(true), - theGambit., Identity>, Identity>>apply( - maybeC -> new Identity<>(maybeC.fmap(c -> parseInt(Character.toString(c)))), - just("321")).runIdentity() - ); + theGambit., Identity, Identity>, Identity>, + Fn1, Identity>>, + Fn1, Identity>>>apply( + maybeC -> new Identity<>(maybeC.fmap(c -> parseInt(Character.toString(c))))) + .apply(just("321")) + .runIdentity()); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/lens/functions/OverTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/OverTest.java similarity index 68% rename from src/test/java/com/jnape/palatable/lambda/lens/functions/OverTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/functions/OverTest.java index e5a95cf4a..ef2adf7a6 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/functions/OverTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/OverTest.java @@ -1,13 +1,13 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.List; import java.util.Set; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.functions.Over.over; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.functions.Over.over; import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/functions/SetTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/SetTest.java similarity index 67% rename from src/test/java/com/jnape/palatable/lambda/lens/functions/SetTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/functions/SetTest.java index 47fa8a959..11a6bdcc5 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/functions/SetTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/SetTest.java @@ -1,12 +1,12 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.List; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.functions.Set.set; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.functions.Set.set; import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/functions/UnderTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/UnderTest.java similarity index 68% rename from src/test/java/com/jnape/palatable/lambda/lens/functions/UnderTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/functions/UnderTest.java index 58d44f19f..15827500b 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/functions/UnderTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/UnderTest.java @@ -1,14 +1,14 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; -import com.jnape.palatable.lambda.lens.Iso; +import com.jnape.palatable.lambda.optics.Iso; import org.junit.Test; import java.util.Collections; import java.util.List; import java.util.Set; -import static com.jnape.palatable.lambda.lens.Iso.iso; -import static com.jnape.palatable.lambda.lens.functions.Under.under; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.functions.Under.under; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/functions/ViewTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/ViewTest.java similarity index 67% rename from src/test/java/com/jnape/palatable/lambda/lens/functions/ViewTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/functions/ViewTest.java index 201ec990a..07f7a047a 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/functions/ViewTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/ViewTest.java @@ -1,13 +1,13 @@ -package com.jnape.palatable.lambda.lens.functions; +package com.jnape.palatable.lambda.optics.functions; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.List; import java.util.Set; -import static com.jnape.palatable.lambda.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/CollectionLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/CollectionLensTest.java similarity index 80% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/CollectionLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/CollectionLensTest.java index 07d88c2de..1c13ef7c9 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/CollectionLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/CollectionLensTest.java @@ -1,6 +1,6 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.ArrayList; @@ -8,10 +8,10 @@ import java.util.List; import java.util.stream.Stream; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.CollectionLens.asCopy; -import static com.jnape.palatable.lambda.lens.lenses.CollectionLens.asSet; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.CollectionLens.asCopy; +import static com.jnape.palatable.lambda.optics.lenses.CollectionLens.asSet; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/EitherLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java similarity index 86% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/EitherLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java index 08bf1d3e3..1d300f389 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/EitherLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java @@ -1,16 +1,16 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static org.junit.Assert.assertEquals; public class EitherLensTest { diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/HListLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/HListLensTest.java similarity index 90% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/HListLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/HListLensTest.java index 6296ff3ef..09c8de717 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/HListLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/HListLensTest.java @@ -1,11 +1,11 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.hlist.Index; import org.junit.Test; import static com.jnape.palatable.lambda.adt.hlist.HList.singletonHList; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.lens.lenses.HListLens.elementAt; +import static com.jnape.palatable.lambda.optics.lenses.HListLens.elementAt; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static testsupport.assertion.LensAssert.assertLensLawfulness; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/HMapLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/HMapLensTest.java similarity index 96% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/HMapLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/HMapLensTest.java index 66073427e..94041fb6e 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/HMapLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/HMapLensTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.hmap.TypeSafeKey; import org.junit.Test; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/IterableLensTest.java similarity index 87% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/IterableLensTest.java index 561bc4d99..3353c9eed 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/IterableLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/IterableLensTest.java @@ -1,17 +1,17 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Iso; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Lens; 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.functions.builtin.fn2.Map.map; -import static com.jnape.palatable.lambda.lens.Iso.simpleIso; -import static com.jnape.palatable.lambda.lens.functions.Over.over; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.Iso.simpleIso; +import static com.jnape.palatable.lambda.optics.functions.Over.over; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/ListLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/ListLensTest.java similarity index 79% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/ListLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/ListLensTest.java index 78949c068..9a283f71c 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/ListLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/ListLensTest.java @@ -1,16 +1,16 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.List; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.ListLens.asCopy; -import static com.jnape.palatable.lambda.lens.lenses.ListLens.elementAt; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.ListLens.asCopy; +import static com.jnape.palatable.lambda.optics.lenses.ListLens.elementAt; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/MapLensTest.java similarity index 94% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/MapLensTest.java index 800dcb876..5a97e5b4a 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/MapLensTest.java @@ -1,6 +1,6 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Test; import java.util.Collection; @@ -11,11 +11,11 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; -import static com.jnape.palatable.lambda.lens.Iso.iso; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.MapLens.keys; -import static com.jnape.palatable.lambda.lens.lenses.MapLens.mappingValues; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.MapLens.keys; +import static com.jnape.palatable.lambda.optics.lenses.MapLens.mappingValues; import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MaybeLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/MaybeLensTest.java similarity index 80% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/MaybeLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/MaybeLensTest.java index 445aa8a73..4542be84b 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MaybeLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/MaybeLensTest.java @@ -1,19 +1,19 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.lens.Lens; +import com.jnape.palatable.lambda.optics.Lens; import org.junit.Before; 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.lens.Lens.lens; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.liftA; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.liftB; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.liftS; -import static com.jnape.palatable.lambda.lens.lenses.MaybeLens.liftT; +import static com.jnape.palatable.lambda.optics.Lens.lens; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.liftA; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.liftB; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.liftS; +import static com.jnape.palatable.lambda.optics.lenses.MaybeLens.liftT; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static testsupport.assertion.LensAssert.assertLensLawfulness; diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/SetLensTest.java similarity index 92% rename from src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java rename to src/test/java/com/jnape/palatable/lambda/optics/lenses/SetLensTest.java index 9421e50f6..6beff4b53 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/SetLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/SetLensTest.java @@ -1,11 +1,11 @@ -package com.jnape.palatable.lambda.lens.lenses; +package com.jnape.palatable.lambda.optics.lenses; import org.junit.Test; import java.util.HashSet; import java.util.TreeSet; -import static com.jnape.palatable.lambda.lens.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.Set.set; import static java.util.Arrays.asList; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; diff --git a/src/test/java/testsupport/assertion/LensAssert.java b/src/test/java/testsupport/assertion/LensAssert.java index e89678afb..b966e97f2 100644 --- a/src/test/java/testsupport/assertion/LensAssert.java +++ b/src/test/java/testsupport/assertion/LensAssert.java @@ -2,10 +2,13 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Map; -import com.jnape.palatable.lambda.lens.LensLike; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.monoid.builtin.Present; +import com.jnape.palatable.lambda.optics.Optic; import java.util.Objects; @@ -15,15 +18,17 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.CartesianProduct.cartesianProduct; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.lang.String.format; import static java.lang.String.join; import static java.util.Arrays.asList; public final class LensAssert { - public static void assertLensLawfulness(LensLike lens, Iterable ss, Iterable bs) { + public static void assertLensLawfulness(Optic, Functor, S, S, A, A> lens, + Iterable ss, + Iterable bs) { Iterable> cases = cartesianProduct(ss, bs); Present.present((x, y) -> join("\n\n", x, y)) .reduceLeft(asList(falsify("You get back what you put in", (s, b) -> view(lens, set(lens, b, s)), (s, b) -> b, cases), diff --git a/src/test/java/testsupport/matchers/LensMatcher.java b/src/test/java/testsupport/matchers/LensMatcher.java deleted file mode 100644 index c25f1fa86..000000000 --- a/src/test/java/testsupport/matchers/LensMatcher.java +++ /dev/null @@ -1,59 +0,0 @@ -package testsupport.matchers; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.lens.Lens; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; - -import java.util.HashSet; - -import static com.jnape.palatable.lambda.functions.builtin.fn1.Empty.empty; -import static com.jnape.palatable.lambda.functions.builtin.fn2.All.all; -import static com.jnape.palatable.lambda.functions.builtin.fn2.CartesianProduct.cartesianProduct; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; -import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection; -import static com.jnape.palatable.lambda.lens.functions.Set.set; -import static com.jnape.palatable.lambda.lens.functions.View.view; - -public class LensMatcher extends BaseMatcher> { - - private final Iterable> combinations; - - private LensMatcher(Iterable> combinations) { - this.combinations = combinations; - } - - @Override - @SuppressWarnings("unchecked") - public boolean matches(Object other) { - if (!(other instanceof Lens)) - return false; - - Lens lens = (Lens) other; - return youGetBackWhatYouPutIn(lens) - && puttingBackWhatYouGotChangesNothing(lens) - && settingTwiceIsEquivalentToSettingOnce(lens); - } - - @Override - public void describeTo(Description description) { - throw new UnsupportedOperationException(); - } - - private boolean youGetBackWhatYouPutIn(Lens lens) { - return all(into((s, b) -> view(lens, set(lens, b, s)).equals(b)), combinations); - } - - private boolean puttingBackWhatYouGotChangesNothing(Lens lens) { - return all(into((s, b) -> set(lens, view(lens, s), s).equals(s)), combinations); - } - - private boolean settingTwiceIsEquivalentToSettingOnce(Lens lens) { - return all(into((s, b) -> set(lens, b, set(lens, b, s)).equals(set(lens, b, s))), combinations); - } - - public static LensMatcher isLawfulForAllSAndB(Iterable ss, Iterable bs) { - return new LensMatcher<>(cartesianProduct(ss, bs)); - } -} From 5a734c52aaf3f1876f57c503de70ba3c29b83266 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 21 Apr 2019 23:14:55 -0500 Subject: [PATCH 133/348] Adding Optic#Simple, updating optic documentation --- .../jnape/palatable/lambda/optics/Iso.java | 10 ++-- .../jnape/palatable/lambda/optics/Lens.java | 2 + .../jnape/palatable/lambda/optics/Optic.java | 54 +++++++++++++++++-- .../lambda/optics/functions/Over.java | 9 ++-- .../lambda/optics/functions/Set.java | 8 +-- .../lambda/optics/functions/View.java | 7 +-- .../palatable/lambda/optics/OpticTest.java | 44 +++++++++++++++ 7 files changed, 115 insertions(+), 19 deletions(-) create mode 100644 src/test/java/com/jnape/palatable/lambda/optics/OpticTest.java diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java index e84ecb048..236c46d07 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -26,7 +26,7 @@ /** * An {@link Iso} (short for "isomorphism") is an invertible {@link Lens}: an {@link Optic} encoding of a * bi-directional focusing of two types, and like {@link Lens}es, can be {@link View}ed, - * {@link Set}, and {@link Over}ed. + * {@link Set}, and {@link Over updated}. *

* As an example, consider the isomorphism between valid {@link String}s and {@link Integer}s: *

@@ -36,9 +36,9 @@
  * String asString = view(stringIntIso.mirror(), 123); // "123"
  * }
  * 
- * In the previous example, stringIntIso can be viewed as a {@link Lens}<String, String, Integer, - * Integer>, and can be {@link Iso#mirror}ed and viewed as a {@link Lens}<Integer, - * Integer, String, String>. + * In the previous example, stringIntIso can be viewed as an + * {@link Optic}<String, String, Integer, Integer>, and can be {@link Iso#mirror}ed and + * viewed as a {@link Optic}<Integer, Integer, String, String>. *

* As with {@link Lens}, variance is supported between S/T and A/B, and where these pairs do * not vary, a {@link Simple} iso can be used (for instance, in the previous example, stringIntIso could @@ -50,6 +50,8 @@ * @param the larger type for mirrored focusing * @param the smaller type for focusing * @param the smaller type for mirrored focusing + * @see Optic + * @see Lens */ @FunctionalInterface public interface Iso extends diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java index c39feabd3..4e2583e03 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java @@ -135,6 +135,8 @@ * @param the type of the "larger" value for putting * @param the type of the "smaller" value that is read * @param the type of the "smaller" update value + * @see Optic + * @see Iso */ @FunctionalInterface public interface Lens extends diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java index c53e200e5..055abf276 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java @@ -15,8 +15,8 @@ * (P<A, F<B>> -> P<S, F<T>>) (existentially-quantified allowing for * covariance). * - * @param

the {@link Profunctor} type - * @param the {@link Functor} type + * @param

the {@link Profunctor} bound + * @param the {@link Functor} bound * @param the left side of the output profunctor * @param the right side's functor embedding of the output profunctor * @param the left side of the input profunctor @@ -156,8 +156,8 @@ default Optic mapB(Function fn) { * Promote a monomorphic function to a compatible {@link Optic}. * * @param fn the function - * @param

the {@link Profunctor} type - * @param the {@link Functor} type + * @param

the {@link Profunctor} bound + * @param the {@link Functor} bound * @param the left side of the output profunctor * @param the right side's functor embedding of the output profunctor * @param the left side of the input profunctor @@ -189,6 +189,28 @@ default Optic mapB(Function fn) { }; } + /** + * Reframe an {@link Optic} according to covariant bounds. + * + * @param optic the {@link Optic} + * @param

the {@link Profunctor} type + * @param the {@link Functor} type + * @param the left side of the output profunctor + * @param the right side's functor embedding of the output profunctor + * @param the left side of the input profunctor + * @param the right side's functor embedding of the input profunctor + * @return the covariantly reframed {@link Optic} + */ + static

, + F extends Functor, + S, T, A, B> Optic reframe(Optic optic) { + return Optic.optic(optic., + Functor, + Profunctor, ? extends P>, + Profunctor, ? extends P>>monomorphize()); + } + interface Simple

, F extends Functor, S, A> extends Optic { @@ -233,5 +255,29 @@ PSFT apply(PAFB pafb) { } }; } + + /** + * Adapt an {@link Optic} with S/T and A/B unified into a {@link Simple simple optic}. + * + * @param optic the {@link Optic} + * @param

the {@link Profunctor} bound + * @param the {@link Functor} bound + * @param the left side and the right side's functor embedding of the output profunctor + * @param the left side and the right side's functor embedding of the input profunctor + * @return the {@link Simple} optic + */ + static

, + F extends Functor, + S, A> Simple adapt(Optic optic) { + return new Simple() { + @Override + public , CoF extends Functor, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return optic.apply(pafb); + } + }; + } } } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java index de8b4a541..cf73de8ad 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java @@ -9,9 +9,9 @@ import java.util.function.Function; /** - * Given a lens, a function from A to B, and a "larger" value S, produce a - * T by retrieving the A from the S, applying the function, and updating the - * S with the B resulting from the function. + * Given an {@link Optic}, a function from A to B, and a "larger" value S, + * produce a T by retrieving the A from the S, applying the function, and + * updating the S with the B resulting from the function. *

* This function is similar to {@link Set}, except that it allows the setting value B to be derived from * S via function application, rather than provided. @@ -23,7 +23,8 @@ * @see Set * @see View */ -public final class Over implements Fn3, ? super Identity, S, T, A, B>, Function, S, T> { +public final class Over implements + Fn3, ? super Identity, S, T, A, B>, Function, S, T> { private static final Over INSTANCE = new Over<>(); diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java index c5c7a7110..d6cc30481 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java @@ -10,11 +10,11 @@ import static com.jnape.palatable.lambda.optics.functions.Over.over; /** - * Given a lens, a "smaller" value B, and a "larger" value S, produce a T by - * lifting the lens into {@link Identity}. + * Given an {@link Optic}, a "smaller" value B, and a "larger" value S, produce a + * T by lifting the {@link Optic} into the {@link Identity} functor. *

- * More idiomatically, this function can be used to treat a lens as a "setter" of Bs on Ss, - * potentially producing a different "larger" value, T. + * More idiomatically, this function can be used to treat an {@link Optic} as a "setter" of + * < code>Bs on Ss, potentially producing a different "larger" value, T. * * @param the type of the larger value * @param the type of the larger updated value diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java index b94992d29..1a80c025e 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java @@ -6,10 +6,11 @@ import com.jnape.palatable.lambda.optics.Optic; /** - * Given a lens and a "larger" value S, retrieve a "smaller" value A by lifting the lens into - * {@link Const}. + * Given an {@link Optic} and a "larger" value S, retrieve a "smaller" value A by lifting the + * {@link Optic} into the {@link Const} functor. *

- * More idiomatically, this function can be used to treat a lens as a "getter" of As from Ss. + * More idiomatically, this function can be used to treat a {@link Optic} as a "getter" of As from + * Ss. * * @param the type of the larger value * @param the type of the larger updated value (unused, but necessary for composition) diff --git a/src/test/java/com/jnape/palatable/lambda/optics/OpticTest.java b/src/test/java/com/jnape/palatable/lambda/optics/OpticTest.java new file mode 100644 index 000000000..00a550185 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/OpticTest.java @@ -0,0 +1,44 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Tagged; +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.optics.Optic.optic; +import static org.junit.Assert.assertEquals; + +public class OpticTest { + + @Test + public void monomorphize() { + Optic, Identity, String, String, String, String> optic = optic(pafb -> pafb); + Fn1>, Tagged>> monomorphize = optic.monomorphize(); + assertEquals(new Identity<>("foo"), monomorphize.apply(new Tagged<>(new Identity<>("foo"))).unTagged()); + } + + @Test + public void reframe() { + Optic, Functor, String, String, String, String> optic = optic(pafb -> pafb); + Optic, Identity, String, String, String, String> reframed = Optic.reframe(optic); + assertEquals(new Identity<>("foo"), + reframed., Identity, Identity, Identity, + Fn1>, + Fn1>>apply(constantly(new Identity<>("foo"))).apply("bar")); + } + + @Test + public void adapt() { + Optic, Functor, String, String, String, String> optic = optic(pafb -> pafb); + Optic.Simple, Functor, String, String> simple = Optic.Simple.adapt(optic); + + assertEquals("foo", + simple., Identity, Identity, Identity, + Fn1>, + Fn1>>apply(constantly(new Identity<>("foo"))) + .apply("bar").runIdentity()); + } +} \ No newline at end of file From 739f8d7831387d6b2efda80da8c56378b35dd8ab Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 4 May 2019 15:17:48 -0500 Subject: [PATCH 134/348] Improving Exchange docs --- .../lambda/functor/builtin/Exchange.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java index d997eaf5d..8d7cc82ea 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.optics.Iso; import java.util.function.Function; @@ -21,30 +22,52 @@ public Exchange(Function sa, FunctionS -> A. + * + * @return a {@link Function}<S, A> + */ public Function sa() { return sa; } + /** + * Extract the mapping B -> T. + * + * @return a {@link Function}<B, T> + */ public Function bt() { return bt; } + /** + * {@inheritDoc} + */ @Override public Exchange diMap(Function lFn, Function rFn) { return new Exchange<>(lFn.andThen(sa), bt.andThen(rFn)); } + /** + * {@inheritDoc} + */ @Override public Exchange diMapL(Function fn) { return (Exchange) Profunctor.super.diMapL(fn); } + /** + * {@inheritDoc} + */ @Override public Exchange diMapR(Function fn) { return (Exchange) Profunctor.super.diMapR(fn); } + /** + * {@inheritDoc} + */ @Override public Exchange contraMap(Function fn) { return (Exchange) Profunctor.super.contraMap(fn); From 3b110037435d0ae276f91633cde35233bdf63c9e Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 4 May 2019 15:23:10 -0500 Subject: [PATCH 135/348] Adjusting variance on Optic.Simple#adapt to be more permissive --- src/main/java/com/jnape/palatable/lambda/optics/Optic.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java index 055abf276..e524d06a9 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java @@ -268,7 +268,7 @@ PSFT apply(PAFB pafb) { */ static

, F extends Functor, - S, A> Simple adapt(Optic optic) { + S, A> Simple adapt(Optic optic) { return new Simple() { @Override public , CoF extends Functor, From 38fe3f702fd53cc64b66dda7324953102db9f0c5 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 4 May 2019 15:23:39 -0500 Subject: [PATCH 136/348] Effect#effect allows function input to be contravariant --- .../java/com/jnape/palatable/lambda/functions/Effect.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index c08a44b01..0074cdd42 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -7,8 +7,8 @@ import java.util.function.Consumer; import java.util.function.Function; -import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.io.IO.io; /** * A function returning "no result", and therefore only useful as a side-effect. @@ -78,7 +78,7 @@ static Effect effect(Runnable runnable) { * @param the effect argument type * @return the effect */ - static Effect effect(Fn1> fn) { + static Effect effect(Fn1> fn) { return a -> fn.apply(a).unsafePerformIO(); } } \ No newline at end of file From 9c969a53db985f143f0fc27fa9409d1cb30e9592 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 4 May 2019 15:25:25 -0500 Subject: [PATCH 137/348] Eliminating warning in Iso in older javac --- .../jnape/palatable/lambda/optics/Iso.java | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java index 236c46d07..ff04ffb26 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -44,7 +44,8 @@ * not vary, a {@link Simple} iso can be used (for instance, in the previous example, stringIntIso could * have had the simplified Iso.Simple<String, Integer> type). *

- * For more information, read about isos. + * For more information, read about + * isos. * * @param the larger type for focusing * @param the larger type for mirrored focusing @@ -119,10 +120,12 @@ default Iso discardR(Applicative> appB) { @Override default Iso flatMap(Function>> fn) { - return unIso().fmap(bt -> Fn2.fn2(fn1(bt.andThen(fn.>andThen(Applicative::coerce)) - .andThen(Iso::unIso) - .andThen(Tuple2::_2) - .andThen(Fn1::fn1)))) + //noinspection RedundantTypeArguments + return unIso().fmap(bt -> Fn2.fn2( + fn1(bt.andThen(fn.>andThen(Monad>::coerce)) + .andThen(Iso::unIso) + .andThen(Tuple2::_2) + .andThen(Fn1::fn1)))) .fmap(Fn2::uncurry) .fmap(bbu -> bbu.diMapL(Tuple2::fill)) .into(Iso::iso); @@ -199,8 +202,10 @@ static Iso iso( Optic, ? super Functor, S, T, A, B> optic) { return new Iso() { @Override - public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { + public >, + CoF extends Functor>, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { return optic.apply(pafb); } }; @@ -250,12 +255,12 @@ default Iso.Simple compose(Iso.Simple g) { */ @SuppressWarnings("overloads") default Iso.Simple andThen(Iso.Simple f) { - return adapt(f.compose(this)); + return Iso.Simple.adapt(f.compose(this)); } @Override default Iso.Simple mirror() { - return adapt(Iso.super.mirror()); + return Iso.Simple.adapt(Iso.super.mirror()); } @Override @@ -265,17 +270,17 @@ default Lens.Simple toLens() { @Override default Iso.Simple discardR(Applicative> appB) { - return adapt(Iso.super.discardR(appB)); + return Iso.Simple.adapt(Iso.super.discardR(appB)); } @Override default Iso.Simple andThen(Optic.Simple, ? super Functor, A, B> f) { - return adapt(Iso.super.andThen(f)); + return Iso.Simple.adapt(Iso.super.andThen(f)); } @Override default Iso.Simple compose(Optic.Simple, ? super Functor, R, S> g) { - return adapt(Iso.super.compose(g)); + return Iso.Simple.adapt(Iso.super.compose(g)); } /** @@ -290,8 +295,10 @@ static Iso.Simple adapt( Optic, ? super Functor, S, S, A, A> optic) { return new Iso.Simple() { @Override - public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { + public >, + CoF extends Functor>, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { return optic.apply(pafb); } }; From 39b772c2566eb7ae0b0e8a9f01931e66e9cda616 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 4 May 2019 18:11:47 -0500 Subject: [PATCH 138/348] Prisms arrive; fixing javadocs --- .../jnape/palatable/lambda/adt/Either.java | 1 - .../palatable/lambda/adt/choice/Choice2.java | 2 - .../palatable/lambda/adt/choice/Choice3.java | 2 - .../palatable/lambda/adt/choice/Choice4.java | 2 - .../palatable/lambda/adt/choice/Choice5.java | 1 - .../palatable/lambda/adt/choice/Choice6.java | 2 - .../palatable/lambda/adt/choice/Choice7.java | 2 - .../palatable/lambda/adt/choice/Choice8.java | 2 - .../jnape/palatable/lambda/functions/Fn1.java | 2 - .../lambda/functions/builtin/fn2/LazyRec.java | 12 +- .../functions/builtin/fn3/FoldRight.java | 10 +- .../lambda/functions/specialized/Pure.java | 14 ++ .../palatable/lambda/functor/Cocartesian.java | 3 +- .../lambda/functor/builtin/Compose.java | 2 - .../lambda/functor/builtin/Const.java | 2 - .../lambda/functor/builtin/Identity.java | 2 - .../lambda/functor/builtin/Market.java | 90 ++++++++ .../lambda/functor/builtin/Tagged.java | 78 +++++++ .../com/jnape/palatable/lambda/io/IO.java | 2 - .../jnape/palatable/lambda/optics/Iso.java | 73 ++++++ .../jnape/palatable/lambda/optics/Lens.java | 70 +++++- .../jnape/palatable/lambda/optics/Optic.java | 19 +- .../jnape/palatable/lambda/optics/Prism.java | 217 ++++++++++++++++++ .../palatable/lambda/optics/ProtoOptic.java | 28 +++ .../lambda/optics/functions/Matching.java | 46 ++++ .../lambda/optics/functions/Pre.java | 60 +++++ .../palatable/lambda/optics/functions/Re.java | 48 ++++ .../lambda/optics/functions/Set.java | 2 +- .../lambda/traversable/LambdaIterable.java | 2 - .../lambda/functor/builtin/MarketTest.java | 29 +++ .../palatable/lambda/optics/PrismTest.java | 51 ++++ .../lambda/optics/functions/PreTest.java | 30 +++ .../lambda/optics/functions/ReTest.java | 27 +++ 33 files changed, 889 insertions(+), 44 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/Prism.java create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/optics/functions/PreTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/optics/functions/ReTest.java 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 85b538c47..242d800e9 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -256,7 +256,6 @@ public final Either zip(Applicative Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index e16315de9..d056ae87c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -115,8 +115,6 @@ public Choice2 zip(Applicative, Choic /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy>> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 953a0ca58..0ba9eddc4 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -115,8 +115,6 @@ public Choice3 zip(Applicative, Ch /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index 8a2efdec7..f24a04042 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -116,8 +116,6 @@ public Choice4 zip(Applicative, /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index fb4a609f3..4008fde0b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -120,7 +120,6 @@ public Choice5 zip(Applicative Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index c3696b1a4..0f09db9fa 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -123,8 +123,6 @@ public Choice6 zip( /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index 4f6c2708c..6965a2d37 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -126,8 +126,6 @@ public Choice7 zip( /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index 28d47e689..a55590886 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -119,8 +119,6 @@ public Choice8 zip( /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 680dc55eb..566ac93db 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -104,8 +104,6 @@ default Fn1 zip(Fn2 appFn) { /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override default Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java index 1e1ffbc8f..7b154b0ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java @@ -17,13 +17,13 @@ *

* Example: *

- * 
- * Lazy lazyFactorial = lazyRec((fact, x) -> x.equals(ONE)
- *                                                               ? lazy(x)
- *                                                               : fact.apply(x.subtract(ONE)).fmap(y -> y.multiply(x)),
+ * {@code
+ * Lazy lazyFactorial = lazyRec((fact, x) -> x.equals(ONE)
+ *                                                       ? lazy(x)
+ *                                                       : fact.apply(x.subtract(ONE)).fmap(y -> y.multiply(x)),
  *                                                  BigInteger.valueOf(50_000));
- * BigInteger value = lazyFactorial.value(); // 3.34732050959714483691547609407148647791277322381045 × 10^213236
- * 
+ * BigInteger value = lazyFactorial.value(); // 3.34732050959714483691547609407148647791277322381045 x 10^213236
+ * }
  * 
* * @param the input type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java index a31648e68..8741aadba 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java @@ -20,15 +20,15 @@ *

* Example: *

- * 
+ * {@code
  * Lazy> lazyCopy = foldRight(
- *     (head, lazyTail) -> lazy(cons(head, () -> lazyTail.value().iterator())),
+ *     (head, lazyTail) -> lazy(cons(head, () -> lazyTail.value().iterator())),
  *     lazy(emptyList()),
- *     iterate(x -> x + 1, 0));
- * Iterable copy = () -> lazyCopy.value().iterator();
+ *     iterate(x -> x + 1, 0));
+ * Iterable copy = () -> lazyCopy.value().iterator();
  * take(3, copy).forEach(System.out::println); // prints "1, 2, 3"
  * take(3, copy).forEach(System.out::println); // prints "1, 2, 3"
- * 
+ * }
  * 
*

* For more information, read about the {@link Functor} to lift into + */ +public interface Pure> { + + Functor apply(A a); +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java b/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java index 8d76e9c45..41bea7f1c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java @@ -26,7 +26,8 @@ public interface Cocartesian> extends Profu /** * Choose between the covariantly-positioned carrier type and the contravariantly-positioned carrier type. This can - * be used to encode partial functions a -> (⊥ v b) as total functions a -> (a v b). + * be used to encode partial functions a -> (_|_ v b) as total functions + * a -> (a v b). * * @return the profunctor with a choice */ diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index b7dcbe209..912ca8109 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -56,8 +56,6 @@ public Compose zip(Applicative, Co /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index 220c41598..e857013a8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -66,8 +66,6 @@ public Const zip(Applicative, Const Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java index 6ade25ffa..e17ae005f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java @@ -63,8 +63,6 @@ public Identity zip(Applicative, Identit /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java new file mode 100644 index 000000000..6929ac661 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java @@ -0,0 +1,90 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Cocartesian; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.choice.Choice2.a; +import static com.jnape.palatable.lambda.adt.choice.Choice2.b; +import static com.jnape.palatable.lambda.functions.Fn1.fn1; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; + +public final class Market implements + Monad>, + Cocartesian> { + + private final Fn1 bt; + private final Fn1> sta; + + public Market(Function bt, Function> sta) { + this.bt = fn1(bt); + this.sta = fn1(sta); + } + + @Override + public Market pure(U u) { + return new Market<>(constantly(u), constantly(left(u))); + } + + @Override + public Market flatMap(Function>> f) { + return new Market<>(b -> f.apply(bt().apply(b)).>coerce().bt().apply(b), + s -> sta().apply(s).invert() + .flatMap(t -> f.apply(t).>coerce().sta() + .apply(s).invert()).invert()); + } + + @Override + public Market zip(Applicative, Market> appFn) { + Market> marketF = appFn.coerce(); + return new Market<>(b -> marketF.bt().apply(b).apply(bt().apply(b)), + s -> sta().apply(s).invert().zip(marketF.sta().apply(s).invert()).invert()); + } + + public Fn1 bt() { + return bt; + } + + public Fn1> sta() { + return sta; + } + + @Override + public Market fmap(Function fn) { + return diMapR(fn); + } + + @Override + public Market, Choice2> cocartesian() { + return new Market<>(bt.fmap(Choice2::b), + cs -> cs.fmap(sta).match(c -> left(a(c)), + tOrA -> tOrA.match(t -> left(b(t)), Either::right))); + } + + @Override + public Market diMap(Function lFn, + Function rFn) { + return new Market<>(bt.fmap(rFn), sta.diMapL(lFn).diMapR(c -> c.biMapL(rFn))); + } + + @Override + public Market diMapL(Function fn) { + return (Market) Cocartesian.super.diMapL(fn); + } + + @Override + public Market diMapR(Function fn) { + return (Market) Cocartesian.super.diMapR(fn); + } + + @Override + public Market contraMap(Function fn) { + return (Market) Cocartesian.super.contraMap(fn); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java new file mode 100644 index 000000000..cebe4973b --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java @@ -0,0 +1,78 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Cocartesian; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.adt.choice.Choice2.b; + +public final class Tagged implements Monad>, Cocartesian> { + private final B b; + + public Tagged(B b) { + this.b = b; + } + + public B unTagged() { + return b; + } + + @Override + public Tagged flatMap(Function>> f) { + return f.apply(b).coerce(); + } + + @Override + public Tagged pure(C c) { + return new Tagged<>(c); + } + + @Override + public Tagged fmap(Function fn) { + return Monad.super.fmap(fn).coerce(); + } + + @Override + public Tagged zip(Applicative, Tagged> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + @Override + public Tagged discardL(Applicative> appB) { + return Monad.super.discardL(appB).coerce(); + } + + @Override + public Tagged discardR(Applicative> appB) { + return Monad.super.discardR(appB).coerce(); + } + + @Override + public Tagged, Choice2> cocartesian() { + return new Tagged<>(b(b)); + } + + @Override + public Tagged diMap(Function lFn, + Function rFn) { + return new Tagged<>(rFn.apply(b)); + } + + @Override + public Tagged diMapL(Function fn) { + return (Tagged) Cocartesian.super.diMapL(fn); + } + + @Override + public Tagged diMapR(Function fn) { + return (Tagged) Cocartesian.super.diMapR(fn); + } + + @Override + public Tagged contraMap(Function fn) { + return (Tagged) Cocartesian.super.contraMap(fn); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index a9d735bc0..29c2e148b 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -122,8 +122,6 @@ public final IO zip(Applicative, IO> /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy> lazyZip(Lazy, IO>> lazyAppFn) { diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java index ff04ffb26..bcb0775d5 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -93,31 +93,49 @@ default Iso mirror() { .biMap(e -> fn1(e.sa()), e -> fn1(e.bt())); } + /** + * {@inheritDoc} + */ @Override default Iso fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override default Iso pure(U u) { return iso(view(this), constantly(u)); } + /** + * {@inheritDoc} + */ @Override default Iso zip(Applicative, Iso> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override default Iso discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override default Iso discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override default Iso flatMap(Function>> fn) { //noinspection RedundantTypeArguments @@ -131,52 +149,82 @@ default Iso flatMap(Function Iso diMapL(Function fn) { return (Iso) Profunctor.super.diMapL(fn); } + /** + * {@inheritDoc} + */ @Override default Iso diMapR(Function fn) { return (Iso) Profunctor.super.diMapR(fn); } + /** + * {@inheritDoc} + */ @Override default Iso diMap(Function lFn, Function rFn) { return this.mapS(lFn).mapT(rFn); } + /** + * {@inheritDoc} + */ @Override default Iso contraMap(Function fn) { return (Iso) Profunctor.super.contraMap(fn); } + /** + * {@inheritDoc} + */ @Override default Iso mapS(Function fn) { return iso(Optic.super.mapS(fn)); } + /** + * {@inheritDoc} + */ @Override default Iso mapT(Function fn) { return iso(Optic.super.mapT(fn)); } + /** + * {@inheritDoc} + */ @Override default Iso mapA(Function fn) { return iso(Optic.super.mapA(fn)); } + /** + * {@inheritDoc} + */ @Override default Iso mapB(Function fn) { return iso(Optic.super.mapB(fn)); } + /** + * {@inheritDoc} + */ @Override default Iso andThen(Optic, ? super Functor, A, B, Z, C> f) { return iso(Optic.super.andThen(f)); } + /** + * {@inheritDoc} + */ @Override default Iso compose(Optic, ? super Functor, R, U, S, T> g) { return iso(Optic.super.compose(g)); @@ -198,6 +246,16 @@ static Iso iso(Function f, return iso(optic(pafb -> pafb.diMap(f, fb -> fb.fmap(g)))); } + /** + * Promote an optic with compatible bounds to an {@link Iso}. + * + * @param optic the {@link Optic} + * @param the larger type for focusing + * @param the larger type for mirrored focusing + * @param the smaller type for focusing + * @param the smaller type for mirrored focusing + * @return the {@link Iso} + */ static Iso iso( Optic, ? super Functor, S, T, A, B> optic) { return new Iso() { @@ -258,26 +316,41 @@ default Iso.Simple andThen(Iso.Simple f) { return Iso.Simple.adapt(f.compose(this)); } + /** + * {@inheritDoc} + */ @Override default Iso.Simple mirror() { return Iso.Simple.adapt(Iso.super.mirror()); } + /** + * {@inheritDoc} + */ @Override default Lens.Simple toLens() { return Lens.Simple.adapt(Iso.super.toLens()); } + /** + * {@inheritDoc} + */ @Override default Iso.Simple discardR(Applicative> appB) { return Iso.Simple.adapt(Iso.super.discardR(appB)); } + /** + * {@inheritDoc} + */ @Override default Iso.Simple andThen(Optic.Simple, ? super Functor, A, B> f) { return Iso.Simple.adapt(Iso.super.andThen(f)); } + /** + * {@inheritDoc} + */ @Override default Iso.Simple compose(Optic.Simple, ? super Functor, R, S> g) { return Iso.Simple.adapt(Iso.super.compose(g)); diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java index 4e2583e03..8b5746c75 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java @@ -144,73 +144,115 @@ public interface Lens extends Monad>, Profunctor> { + /** + * {@inheritDoc} + */ @Override default Lens fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override default Lens pure(U u) { return lens(view(this), (s, b) -> u); } + /** + * {@inheritDoc} + */ @Override default Lens zip(Applicative, Lens> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override default Lens discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override default Lens discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override default Lens flatMap(Function>> f) { return lens(view(this), (s, b) -> set(f.apply(set(this, b, s)).>coerce(), b, s)); } + /** + * {@inheritDoc} + */ @Override default Lens diMapL(Function fn) { return (Lens) Profunctor.super.diMapL(fn); } + /** + * {@inheritDoc} + */ @Override default Lens diMapR(Function fn) { return (Lens) Profunctor.super.diMapR(fn); } + /** + * {@inheritDoc} + */ @Override default Lens diMap(Function lFn, Function rFn) { return this.mapS(lFn).mapT(rFn); } + /** + * {@inheritDoc} + */ @Override default Lens contraMap(Function fn) { return (Lens) Profunctor.super.contraMap(fn); } + /** + * {@inheritDoc} + */ @Override default Lens mapS(Function fn) { return lens(Optic.super.mapS(fn)); } + /** + * {@inheritDoc} + */ @Override default Lens mapT(Function fn) { return lens(Optic.super.mapT(fn)); } + /** + * {@inheritDoc} + */ @Override default Lens mapA(Function fn) { return lens(Optic.super.mapA(fn)); } + /** + * {@inheritDoc} + */ @Override default Lens mapB(Function fn) { return lens(Optic.super.mapB(fn)); @@ -226,11 +268,17 @@ default Iso toIso(S s) { return iso(view(this), set(this).flip().apply(s)); } + /** + * {@inheritDoc} + */ @Override default Lens andThen(Optic, ? super Functor, A, B, C, D> f) { return lens(Optic.super.andThen(f)); } + /** + * {@inheritDoc} + */ @Override default Lens compose(Optic, ? super Functor, R, U, S, T> g) { return lens(Optic.super.compose(g)); @@ -258,11 +306,23 @@ static Lens lens(Function gette .fmap(b -> setter.apply(s, b)))); } + /** + * Promote an optic with compatible bounds to a {@link Lens}. + * + * @param optic the {@link Optic} + * @param the type of the "larger" value for reading + * @param the type of the "larger" value for putting + * @param the type of the "smaller" value that is read + * @param the type of the "smaller" update value + * @return the {@link Lens} + */ static Lens lens(Optic, ? super Functor, S, T, A, B> optic) { return new Lens() { @Override - public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { + public >, CoF extends Functor>, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { return optic.apply(pafb); } }; @@ -323,11 +383,17 @@ static Lens.Simple> both(Lens.Simple f, Lens.Sim @FunctionalInterface interface Simple extends Lens, Optic.Simple, Functor, S, A> { + /** + * {@inheritDoc} + */ @Override default Lens.Simple andThen(Optic.Simple, ? super Functor, A, B> f) { return Lens.Simple.adapt(Lens.super.andThen(f)); } + /** + * {@inheritDoc} + */ @Override default Lens.Simple compose(Optic.Simple, ? super Functor, R, S> g) { return Lens.Simple.adapt(Lens.super.compose(g)); diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java index e524d06a9..4eeac4f75 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java @@ -37,6 +37,8 @@ public interface Optic

, F extends Functo * * @param the covariant bound on P * @param the covariant bound on F + * @param fixed functor over B for inference + * @param fixed functor over T for inference * @param the fixed input profunctor type * @param the fixed output profunctor type * @return the monomorphic {@link Fn1} backed by this {@link Optic} @@ -52,7 +54,7 @@ Fn1 monomorphize() { } /** - * Left-to-right composition of optics. Requires compatibility between S> and T. + * Left-to-right composition of optics. Requires compatibility between S and T. * * @param f the other optic * @param the new left side of the input profunctor @@ -162,6 +164,8 @@ default Optic mapB(Function fn) { * @param the right side's functor embedding of the output profunctor * @param the left side of the input profunctor * @param the right side's functor embedding of the input profunctor + * @param fixed functor over B for inference + * @param fixed functor over T for inference * @param the input * @param the output * @return the {@link Optic} @@ -211,8 +215,17 @@ S, T, A, B> Optic reframe(Optic, ? extends P>>monomorphize()); } - interface Simple

, F extends Functor, S, A> extends - Optic { + /** + * An convenience type with a simplified signature for {@link Optic optics} with unified S/T and + * A/B types. + * + * @param

the {@link Profunctor} bound + * @param the {@link Functor} bound + * @param the left side and right side's functor embedding of the output profunctor + * @param the left side and right side's functor embedding of the input profunctor + */ + interface Simple

, F extends Functor, S, A> + extends Optic { /** * Compose two simple optics from left to right. diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java new file mode 100644 index 000000000..bf2afb487 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -0,0 +1,217 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Cocartesian; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Market; +import com.jnape.palatable.lambda.optics.functions.Matching; +import com.jnape.palatable.lambda.optics.functions.Pre; +import com.jnape.palatable.lambda.optics.functions.Re; +import com.jnape.palatable.lambda.optics.functions.View; + +import java.util.function.Function; + +/** + * Prisms are {@link Iso Isos} that can fail in one direction. Example: + *

+ * {@code
+ * Prism parseInt =
+ *     prism(str -> Either.trying(() -> Integer.parseInt(str),
+ *                                constantly(str)),
+ *           Object::toString);
+ *
+ * String         str   = view(re(parseInt), 123); // "123"
+ * Maybe works = view(pre(parseInt), "123"); // Just 123
+ * Maybe fails = view(pre(parseInt), "foo"); // Nothing
+ * }
+ * 
+ *

+ * Note that because a {@link Prism} might fail in one direction, it cannot be immediately used for + * {@link View viewing}; however, the combinators {@link Re re}, {@link Pre pre}, and {@link Matching matching} can all + * be used to provide the additional context to a {@link Prism} so it can be used for viewing. + * + * @param the input that might fail to map to its output + * @param the guaranteed output + * @param the output that might fail to be produced + * @param the input that guarantees its output + */ +@FunctionalInterface +public interface Prism extends + ProtoOptic, S, T, A, B>, + Optic, Identity, S, T, A, B> { + + @Override + default >, + CoF extends Functor>, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + @SuppressWarnings("RedundantTypeArguments") + Optic, Identity, S, T, A, B> optic = this.>toOptic(Identity::new); + return optic.apply(pafb); + } + + /** + * Recover the two mappings encapsulated by this {@link Prism} by sending it through a {@link Market}. + * + * @return a {@link Tuple2 tuple} of the two mappings encapsulated by this {@link Prism} + */ + default Tuple2, Function>> unPrism() { + return Tuple2.fill(this., Identity, Identity, Identity, + Market>, Market>>apply( + new Market<>(Identity::new, Either::right)).fmap(Identity::runIdentity)) + .biMap(Market::bt, Market::sta); + } + + /** + * Static factory method for creating a {@link Prism} given a mapping from + * S -> {@link Either}<T, A> and a mapping from B -> T. + * + * @param sta the mapping from S -> {@link Either}<T, A> + * @param bt the mapping from B -> T + * @param the input that might fail to map to its output + * @param the guaranteed output + * @param the output that might fail to be produced + * @param the input that guarantees its output + * @return the {@link Prism} + */ + static Prism prism(Function> sta, + Function bt) { + return new Prism() { + @Override + public > Optic, F, S, T, A, B> toOptic( + Pure pure) { + return Optic., + F, + S, T, A, B, + Functor, + Functor, + Cocartesian, ?>, + Cocartesian, ?>>optic(pafb -> pafb.cocartesian() + .diMap(s -> sta.apply(s).match(Choice2::a, Choice2::b), + tOrFb -> tOrFb.match(pure::apply, fb -> fb.fmap(bt)))); + } + }; + } + + /** + * Promote a {@link ProtoOptic} with compatible bounds to an {@link Prism}. + * + * @param protoOptic the {@link ProtoOptic} + * @param the input that might fail to map to its output + * @param the guaranteed output + * @param the output that might fail to be produced + * @param the input that guarantees its output + * @return the {@link Prism} + */ + static Prism prism(ProtoOptic, S, T, A, B> protoOptic) { + return new Prism() { + @Override + public > Optic, F, S, T, A, B> toOptic( + Pure pure) { + Optic, F, S, T, A, B> optic = protoOptic.toOptic(pure); + return Optic.reframe(optic); + } + }; + } + + /** + * Promote an {@link Optic} with compatible bounds to an {@link Prism}. Note that because the {@link Optic} must + * guarantee an unbounded {@link Functor} constraint in order to satisfy any future covariant constraint, the + * resulting {@link Prism prism's} toOptic method will never need to consult its given + * {@link Pure lifting} function. + * + * @param optic the {@link Optic} + * @param the input that might fail to map to its output + * @param the guaranteed output + * @param the output that might fail to be produced + * @param the input that guarantees its output + * @return the {@link Prism} + */ + static Prism prism( + Optic, ? super Functor, S, T, A, B> optic) { + return new Prism() { + @Override + public > Optic, F, S, T, A, B> toOptic( + Pure pure) { + return Optic.reframe(optic); + } + }; + } + + /** + * Static factory method for creating a simple {@link Prism} from a function and its potentially failing inverse. + * + * @param sMaybeA a partial mapping from S -> A + * @param as a total mapping from A -> S + * @param the input that might fail to map to its output and the guaranteed output from the other direction + * @param the output that might fail to be produced and the input that guarantees its output in the other + * direction + * @return the {@link Simple simple prism} + */ + static Prism.Simple simplePrism(Function> sMaybeA, + Function as) { + return Prism.prism(s -> sMaybeA.apply(s).toEither(() -> s), as)::toOptic; + } + + /** + * A convenience type with a simplified type signature for common {@link Prism prism} with unified S/T + * and A/B types. + * + * @param the input that might fail to map to its output and the guaranteed output from the other direction + * @param the output that might fail to be produced and the input that guarantees its output in the other + * direction + */ + interface Simple extends Prism { + + /** + * Adapt a {@link Prism} with compatible bounds to a {@link Prism.Simple simple Prism}. + * + * @param prism the {@link Prism} + * @param the input that might fail to map to its output and the guaranteed output from the other + * direction + * @param the output that might fail to be produced and the input that guarantees its output in the other + * direction + * @return the {@link Prism.Simple simple Prism} + */ + static Prism.Simple adapt(Prism prism) { + return prism::toOptic; + } + + /** + * Adapt a {@link ProtoOptic} with compatible bounds to a {@link Prism.Simple simple Prism}. + * + * @param protoOptic the {@link ProtoOptic} + * @param the input that might fail to map to its output and the guaranteed output from the other + * direction + * @param the output that might fail to be produced and the input that guarantees its output in the + * other direction + * @return the {@link Prism.Simple simple Prism} + */ + static Prism.Simple adapt(ProtoOptic, S, S, A, A> protoOptic) { + return adapt(prism(protoOptic)); + } + + /** + * Adapt an {@link Optic} with compatible bounds to a {@link Prism.Simple simple Prism}. + * + * @param optic the {@link Optic} + * @param the input that might fail to map to its output and the guaranteed output from the other + * direction + * @param the output that might fail to be produced and the input that guarantees its output in the + * other direction + * @return the {@link Prism.Simple simple Prism} + */ + static Prism.Simple adapt( + Optic, ? super Functor, S, S, A, A> optic) { + return adapt(prism(optic)); + } + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java b/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java new file mode 100644 index 000000000..1d38ef807 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java @@ -0,0 +1,28 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.Profunctor; + +/** + * A generic supertype representation for a profunctor {@link Optic} that requires a {@link Pure} implementation to + * derive its {@link Functor} constraint and graduate to a full-fledge {@link Optic}. + * + * @param

the {@link Profunctor} bound + * @param the left side of the output profunctor + * @param the right side's functor embedding of the output profunctor + * @param the left side of the input profunctor + * @param the right side's functor embedding of the input profunctor + */ +public interface ProtoOptic

, S, T, A, B> { + + /** + * Given a {@link Pure} lifting function, fix this {@link ProtoOptic} to the given {@link Functor} and promote it to + * an {@link Optic}. + * + * @param pure the {@link Pure} lifting function + * @param the {@link Functor} bound + * @return the {@link Optic} + */ + > Optic toOptic(Pure pure); +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java new file mode 100644 index 000000000..425f47dcf --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java @@ -0,0 +1,46 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Market; +import com.jnape.palatable.lambda.optics.Optic; + +public final class Matching implements + Fn2, ? super Identity, S, T, A, B>, S, Either> { + + private static final Matching INSTANCE = new Matching<>(); + + private Matching() { + } + + @Override + public Either apply(Optic, ? super Identity, S, T, A, B> optic, S s) { + Market> market = new Market<>(Identity::new, Either::right); + return optic., + Identity, + Identity, + Identity, + Market>, + Market>> + apply(market).sta().apply(s) + .biMapL(Identity::runIdentity) + .match(Either::left, Either::right); + } + + @SuppressWarnings("unchecked") + public static Matching matching() { + return (Matching) INSTANCE; + } + + public static Fn1> matching( + Optic, ? super Identity, S, T, A, B> optic) { + return Matching.matching().apply(optic); + } + + public static Either matching( + Optic, ? super Identity, S, T, A, B> optic, S s) { + return matching(optic).apply(s); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java new file mode 100644 index 000000000..edbd9e9c0 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java @@ -0,0 +1,60 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.builtin.Const; +import com.jnape.palatable.lambda.optics.Optic; +import com.jnape.palatable.lambda.optics.ProtoOptic; + +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.optics.Optic.reframe; + +/** + * Turn an {@link Optic} with a unary mapping that can be used for viewing some number of values into an {@link Optic} + * that views the first value, if it exists. + * + * @param the value to read from + * @param used for unification of the {@link Optic optic's} unused morphism + * @param the result to {@link Maybe maybe} read out + * @param used for unification of the {@link Optic optic's} unused morphism + */ +public final class Pre implements Fn1, ? super Const, ?>, S, T, A, B>, + Optic, Const, ?>, S, T, Maybe, B>> { + + private static final Pre INSTANCE = new Pre<>(); + + private Pre() { + } + + @Override + public Optic, Const, ?>, S, T, Maybe, B> apply( + Optic, ? super Const, ?>, S, T, A, B> optic) { + Optic, ? super Const, ?>, S, T, Maybe, B> mappedOptic = optic.mapA(Maybe::just); + return reframe(mappedOptic); + } + + @SuppressWarnings("unchecked") + public static Pre pre() { + return (Pre) INSTANCE; + } + + @SuppressWarnings("overloads") + public static Optic, Const, ?>, S, T, Maybe, B> pre( + Optic, ? super Const, ?>, S, T, A, B> optic) { + return Pre.pre().apply(optic); + } + + @SuppressWarnings("overloads") + public static Optic, Const, ?>, S, T, Maybe, B> pre( + ProtoOptic, S, T, A, B> protoOptic) { + Optic, Const, ?>, S, T, A, B> optic = protoOptic + .toOptic(new Pure, ?>>() { + @Override + public Const, X> apply(X x) { + return new Const<>(nothing()); + } + }); + return pre(optic); + } +} \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java new file mode 100644 index 000000000..a61841058 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java @@ -0,0 +1,48 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Const; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Tagged; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Optic; +import com.jnape.palatable.lambda.optics.Prism; + +/** + * Turn an {@link Optic} with a unary mapping that can be used for setting (e.g. {@link Prism}, {@link Iso}) around for + * viewing through the other direction. + * + * @param used for unification of the {@link Optic optic's} unused morphism + * @param the result to read out + * @param used for unification of the {@link Optic optic's} unused morphism + * @param the value to read from + */ +public final class Re implements + Fn1, ? super Identity, S, T, A, B>, Optic, Const, B, B, T, T>> { + + private static final Re INSTANCE = new Re<>(); + + private Re() { + } + + @Override + public Optic, Const, B, B, T, T> apply( + Optic, ? super Identity, S, T, A, B> optic) { + return Optic., Const, B, B, T, T, + Const, Const, + Fn1>, + Fn1>>optic(pafb -> b -> new Const<>(optic., Identity, Identity, + Identity, Tagged>, + Tagged>>apply(new Tagged<>(new Identity<>(b))).unTagged().runIdentity())); + } + + @SuppressWarnings("unchecked") + public static Re re() { + return (Re) INSTANCE; + } + + public static Optic, Const, B, B, T, T> re( + Optic, ? super Identity, S, T, A, B> optic) { + return Re.re().apply(optic); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java index d6cc30481..1921c45c6 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java @@ -14,7 +14,7 @@ * T by lifting the {@link Optic} into the {@link Identity} functor. *

* More idiomatically, this function can be used to treat an {@link Optic} as a "setter" of - * < code>Bs on Ss, potentially producing a different "larger" value, T. + * Bs on Ss, potentially producing a different "larger" value, T. * * @param the type of the larger value * @param the type of the larger updated value 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 5ef35da8e..09222e719 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -73,8 +73,6 @@ public LambdaIterable zip(Applicative, L /** * {@inheritDoc} - * - * @param lazyAppFn */ @Override public Lazy> lazyZip( diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java new file mode 100644 index 000000000..d4009918e --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java @@ -0,0 +1,29 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Either.trying; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static java.lang.Integer.parseInt; + +@RunWith(Traits.class) +public class MarketTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public Subjects, String>> testSubject() { + Market market = new Market<>(id(), str -> trying(() -> parseInt(str), + constantly(str))); + return subjects(new EquatableM<>(market, m -> both(m.bt(), m.sta(), "123")), + new EquatableM<>(market, m -> both(m.bt(), m.sta(), "foo"))); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java new file mode 100644 index 000000000..47b76efdb --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java @@ -0,0 +1,51 @@ +package com.jnape.palatable.lambda.optics; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.functions.Fn1; +import org.junit.Test; + +import java.util.function.Function; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static com.jnape.palatable.lambda.optics.Prism.simplePrism; +import static com.jnape.palatable.lambda.optics.functions.Matching.matching; +import static com.jnape.palatable.lambda.optics.functions.Pre.pre; +import static com.jnape.palatable.lambda.optics.functions.Re.re; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static org.junit.Assert.assertEquals; + +public class PrismTest { + + private static final Fn1 PARSE_INT = Fn1.fn1(Integer::parseInt); + + @Test + public void prismLaws() { + Prism prism = prism(PARSE_INT.choose(), Object::toString); + + assertEquals(just(1), view(pre(prism), view(re(prism), 1))); + assertEquals(just(123), view(pre(prism), "123").filter(a -> view(re(prism), a).equals("123"))); + assertEquals(left("foo"), matching(prism, "foo").match(t -> matching(prism, t), Either::right)); + } + + @Test + @SuppressWarnings("unused") + public void simplePrismInference() { + Prism.Simple simplePrism = simplePrism(PARSE_INT.choose().fmap(CoProduct2::projectB), + Object::toString); + } + + @Test + public void unPrismExtractsMappings() { + Prism prism = prism(PARSE_INT.choose(), Object::toString); + Function is = prism.unPrism()._1(); + Function> sis = prism.unPrism()._2(); + + assertEquals("123", is.apply(123)); + assertEquals(right(123), sis.apply("123")); + assertEquals(left("foo"), sis.apply("foo")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/functions/PreTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/PreTest.java new file mode 100644 index 000000000..d697108ee --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/PreTest.java @@ -0,0 +1,30 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Prism; +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.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static com.jnape.palatable.lambda.optics.functions.Pre.pre; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static java.lang.Integer.parseInt; +import static org.junit.Assert.assertEquals; + +public class PreTest { + + @Test + public void focusOnAtMostOneValue() { + Iso iso = iso(Integer::parseInt, Object::toString); + Prism prism = prism(s -> Either.trying(() -> parseInt(s), + constantly(s)), + Object::toString); + assertEquals(just(1), view(pre(prism), "1")); + assertEquals(nothing(), view(pre(prism), "foo")); + assertEquals(just(1), view(pre(iso), "1")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/functions/ReTest.java b/src/test/java/com/jnape/palatable/lambda/optics/functions/ReTest.java new file mode 100644 index 000000000..a6d4fb900 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/functions/ReTest.java @@ -0,0 +1,27 @@ +package com.jnape.palatable.lambda.optics.functions; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.optics.Iso; +import com.jnape.palatable.lambda.optics.Prism; +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.optics.Iso.iso; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static com.jnape.palatable.lambda.optics.functions.Re.re; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static java.lang.Integer.parseInt; +import static org.junit.Assert.assertEquals; + +public class ReTest { + + @Test + public void flipAroundIsoAndPrism() { + Iso iso = iso(Integer::parseInt, Object::toString); + Prism prism = prism(s -> Either.trying(() -> parseInt(s), + constantly(s)), + Object::toString); + assertEquals("1", view(re(prism), 1)); + assertEquals("1", view(re(iso), 1)); + } +} \ No newline at end of file From a79e760f3796934e683fd9acfcceca6081cd03fc Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 4 May 2019 18:17:12 -0500 Subject: [PATCH 139/348] Adding missing javadoc --- .../lambda/functor/builtin/Market.java | 62 ++++++++++++++++--- .../lambda/functor/builtin/Tagged.java | 45 ++++++++++++++ 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java index 6929ac661..efb2e0247 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cocartesian; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.optics.Prism; import java.util.function.Function; @@ -15,6 +16,14 @@ import static com.jnape.palatable.lambda.functions.Fn1.fn1; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +/** + * A profunctor used to extract the isomorphic functions a {@link Prism} is composed of. + * + * @param the output that might fail to be produced + * @param the input that guarantees its output + * @param the input that might fail to map to its output + * @param the guaranteed output + */ public final class Market implements Monad>, Cocartesian> { @@ -27,11 +36,35 @@ public Market(Function bt, FunctionB -> T. + * + * @return a {@link Function}<B, T> + */ + public Fn1 bt() { + return bt; + } + + /** + * Extract the mapping S -> {@link Either}<T, A>. + * + * @return a {@link Function}<S, {@link Either}<T, A>> + */ + public Fn1> sta() { + return sta; + } + + /** + * {@inheritDoc} + */ @Override public Market pure(U u) { return new Market<>(constantly(u), constantly(left(u))); } + /** + * {@inheritDoc} + */ @Override public Market flatMap(Function>> f) { return new Market<>(b -> f.apply(bt().apply(b)).>coerce().bt().apply(b), @@ -40,6 +73,9 @@ public Market flatMap(Function Market zip(Applicative, Market> appFn) { Market> marketF = appFn.coerce(); @@ -47,19 +83,17 @@ public Market zip(Applicative, s -> sta().apply(s).invert().zip(marketF.sta().apply(s).invert()).invert()); } - public Fn1 bt() { - return bt; - } - - public Fn1> sta() { - return sta; - } - + /** + * {@inheritDoc} + */ @Override public Market fmap(Function fn) { return diMapR(fn); } + /** + * {@inheritDoc} + */ @Override public Market, Choice2> cocartesian() { return new Market<>(bt.fmap(Choice2::b), @@ -67,22 +101,34 @@ public Market, Choice2> cocartesian() { tOrA -> tOrA.match(t -> left(b(t)), Either::right))); } + /** + * {@inheritDoc} + */ @Override public Market diMap(Function lFn, Function rFn) { return new Market<>(bt.fmap(rFn), sta.diMapL(lFn).diMapR(c -> c.biMapL(rFn))); } + /** + * {@inheritDoc} + */ @Override public Market diMapL(Function fn) { return (Market) Cocartesian.super.diMapL(fn); } + /** + * {@inheritDoc} + */ @Override public Market diMapR(Function fn) { return (Market) Cocartesian.super.diMapR(fn); } + /** + * {@inheritDoc} + */ @Override public Market contraMap(Function fn) { return (Market) Cocartesian.super.contraMap(fn); diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java index cebe4973b..3b2ea5e79 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java @@ -9,6 +9,13 @@ import static com.jnape.palatable.lambda.adt.choice.Choice2.b; +/** + * Like {@link Const}, but the phantom parameter is in the contravariant position, and the value is in covariant + * position. + * + * @param the phantom type + * @param the value type + */ public final class Tagged implements Monad>, Cocartesian> { private final B b; @@ -16,61 +23,99 @@ public Tagged(B b) { this.b = b; } + /** + * Extract the contained value. + * + * @return the value + */ public B unTagged() { return b; } + /** + * {@inheritDoc} + */ @Override public Tagged flatMap(Function>> f) { return f.apply(b).coerce(); } + /** + * {@inheritDoc} + */ @Override public Tagged pure(C c) { return new Tagged<>(c); } + /** + * {@inheritDoc} + */ @Override public Tagged fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override public Tagged zip(Applicative, Tagged> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override public Tagged discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Tagged discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public Tagged, Choice2> cocartesian() { return new Tagged<>(b(b)); } + /** + * {@inheritDoc} + */ @Override public Tagged diMap(Function lFn, Function rFn) { return new Tagged<>(rFn.apply(b)); } + /** + * {@inheritDoc} + */ @Override public Tagged diMapL(Function fn) { return (Tagged) Cocartesian.super.diMapL(fn); } + /** + * {@inheritDoc} + */ @Override public Tagged diMapR(Function fn) { return (Tagged) Cocartesian.super.diMapR(fn); } + /** + * {@inheritDoc} + */ @Override public Tagged contraMap(Function fn) { return (Tagged) Cocartesian.super.contraMap(fn); From 45724d530298f74aa5c0cc6ea480131d11a71030 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 4 May 2019 18:39:55 -0500 Subject: [PATCH 140/348] LazyT, a monad transformer for Lazy --- CHANGELOG.md | 5 + .../lambda/functor/builtin/Lazy.java | 31 ++++- .../monad/transformer/builtin/LazyT.java | 126 ++++++++++++++++++ .../monad/transformer/builtin/LazyTTest.java | 36 +++++ 4 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 1263a8cf1..b79a97dbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,10 +24,15 @@ might need to be reworked, and subtyping is obviously no longer supported. - `MaybeT`, a monad transformer for `Maybe` - `EitherT`, a monad transformer for `Either` - `IdentityT`, a monad transformer for `Identity` +- `LazyT`, a monad transformer for `Lazy` - `Endo`, a monoid formed by `Fn1` under composition - `State`, the state `Monad` - `Downcast`, a function supporting unchecked down-casting - `Cocartesian`, profunctorial strength in cocartesian coproduct terms +- `Prism`, an `Optic` that is nearly an `Iso` but can fail in one direction +- `Market`, `Tagged`, profunctors supporting optics +- `Re` for viewing an `Optic` in one direction reliably +- `Pre` for viewing at most one value from an `Optic` in one direction ## [3.3.0] - 2019-02-18 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java index f3f4be0ac..ea1bef9cd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java @@ -4,8 +4,10 @@ import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.traversable.Traversable; import java.util.LinkedList; +import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; @@ -21,7 +23,7 @@ * * @param the value type */ -public abstract class Lazy implements Monad> { +public abstract class Lazy implements Monad>, Traversable> { private Lazy() { } @@ -44,6 +46,18 @@ public Lazy flatMap(Function>> f) { return new Compose<>(source, flatMap); } + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public , TravB extends Traversable>, + AppB extends Applicative, + AppTrav extends Applicative> AppTrav traverse(Function fn, + Function pure) { + return fn.apply(value()).fmap(b -> (TravB) lazy(b)).coerce(); + } + /** * {@inheritDoc} */ @@ -84,6 +98,21 @@ public final Lazy discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + @Override + public boolean equals(Object other) { + return other instanceof Lazy && Objects.equals(value(), ((Lazy) other).value()); + } + + @Override + public int hashCode() { + return Objects.hash(value()); + } + + @Override + public String toString() { + return "Lazy{value=" + value() + "}"; + } + /** * Lift a pure value into a lazy computation. * diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java new file mode 100644 index 000000000..fe10e8142 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java @@ -0,0 +1,126 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.builtin.Compose; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import java.util.Objects; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; + +/** + * A {@link MonadT monad transformer} for {@link Lazy}. Note that {@link LazyT#flatMap(Function)} must force its value. + * + * @param the outer {@link Monad} + * @param the carrier type + */ +public class LazyT, A> implements MonadT, A> { + + private final Monad, M> mla; + + private LazyT(Monad, M> mla) { + this.mla = mla; + } + + /** + * {@inheritDoc} + */ + @Override + public >, FGA extends Monad> FGA run() { + return mla.fmap(Functor::coerce).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT flatMap(Function, ?>>> f) { + return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value())., B>>coerce().run())); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT pure(B b) { + return new LazyT<>(mla.pure(lazy(b))); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT fmap(Function fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT zip(Applicative, MonadT, ?>> appFn) { + return MonadT.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, MonadT, ?>>> lazyAppFn) { + return new Compose<>(mla) + .lazyZip(lazyAppFn.fmap(lazyT -> new Compose<>( + lazyT.>>coerce() + .>, + Monad>, M>>run()))) + .fmap(compose -> lazyT(compose.getCompose())); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT discardL(Applicative, ?>> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public LazyT discardR(Applicative, ?>> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + @Override + public boolean equals(Object other) { + return other instanceof LazyT && Objects.equals(mla, ((LazyT) other).mla); + } + + @Override + public int hashCode() { + return Objects.hash(mla); + } + + @Override + public String toString() { + return "LazyT{mla=" + mla + '}'; + } + + /** + * Static factory method for lifting a {@link Monad}<{@link Lazy}<A>, M> into a + * {@link LazyT}. + * + * @param mla the {@link Monad}<{@link Lazy}<A>, M> + * @param the outer {@link Monad} unification parameter + * @param the carrier type + * @return the new {@link LazyT} + */ + public static , A> LazyT lazyT(Monad, M> mla) { + return new LazyT<>(mla); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java new file mode 100644 index 000000000..87dffb7e6 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java @@ -0,0 +1,36 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.monad.transformer.builtin.LazyT.lazyT; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class LazyTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public LazyT, Integer> testSubject() { + return lazyT(just(lazy(1))); + } + + @Test + public void lazyZip() { + assertEquals(lazyT(just(lazy(2))), + lazyT(just(lazy(1))) + .lazyZip(lazy(lazyT(just(lazy(x -> x + 1))))).value()); + assertEquals(lazyT(nothing()), + lazyT(nothing()).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } +} \ No newline at end of file From 47969896958f1ae415eabb8cfca207f66c7948cf Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 5 May 2019 21:22:16 -0500 Subject: [PATCH 141/348] Try/Either no longer attempt in vain to preserve Throwable type --- CHANGELOG.md | 2 + .../jnape/palatable/lambda/adt/Either.java | 18 +-- .../com/jnape/palatable/lambda/adt/Try.java | 125 +++++++----------- .../specialized/checked/Runtime.java | 5 +- .../iteration/RateLimitingIterator.java | 10 +- .../jnape/palatable/lambda/adt/TryTest.java | 40 +++--- .../functions/builtin/fn4/RateLimitTest.java | 12 +- 7 files changed, 96 insertions(+), 116 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b79a97dbe..cda581167 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ might need to be reworked, and subtyping is obviously no longer supported. - ***Breaking Change***: `Strong` is now called `Cartesian` to better reflect the type of strength - ***Breaking Change***: new Optic type hierarchy more faithfully encodes profunctor constraints on optics, new `Optic` type is now the supertype of `Lens` and `Iso`, and `lens` package has been moved to `optics` +- ***Breaking Change***: Try and Either no longer preserve `Throwable` type since it was inherently not type-safe + anyway; Try is therefore no longer a `Bifunctor` - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ### Added 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 242d800e9..bda1b4fa2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -323,14 +323,13 @@ public static Either fromMaybe(Maybe maybe, Supplier leftFn) * * @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 */ - public static Either trying(CheckedSupplier supplier, - Function leftFn) { - return Try.trying(supplier::get).toEither(leftFn); + public static Either trying(CheckedSupplier supplier, + Function leftFn) { + return Try.trying(supplier::get).toEither(leftFn); } /** @@ -338,11 +337,10 @@ 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) { + public static Either trying(CheckedSupplier supplier) { return trying(supplier, id()); } @@ -352,12 +350,11 @@ public static Either trying(CheckedSupplier * * @param runnable the runnable * @param leftFn a function mapping E to L - * @param the most contravariant exception that the runnable might throw * @param the left parameter type * @return {@link Unit} as a right value, or leftFn's mapping result as a left value */ - public static Either trying(CheckedRunnable runnable, - Function leftFn) { + public static Either trying(CheckedRunnable runnable, + Function leftFn) { return Try.trying(runnable).toEither(leftFn); } @@ -366,10 +363,9 @@ public static Either trying(CheckedRunnable * exception, wrap it in a left value and return it. * * @param runnable the runnable - * @param the left parameter type (the most contravariant exception that runnable might throw) * @return {@link Unit} as a right value, or a left value of the thrown exception */ - public static Either trying(CheckedRunnable runnable) { + public static Either trying(CheckedRunnable runnable) { return trying(runnable, id()); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index 4b0e24b19..fddedbb37 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -4,8 +4,8 @@ import com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1; import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable; import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.BoundedBifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -18,18 +18,16 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek2.peek2; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * A {@link Monad} of the evaluation outcome of an expression that might throw. Try/catch/finally semantics map to * trying/catching/ensuring, respectively. * - * @param the {@link Throwable} type that may have been thrown by the expression * @param the possibly successful expression result * @see Either */ -public abstract class Try implements Monad>, Traversable>, BoundedBifunctor>, CoProduct2> { +public abstract class Try implements Monad>, Traversable>, CoProduct2> { private Try() { } @@ -43,7 +41,8 @@ private Try() { * @return a new {@link Try} instance around either the original successful result or the mapped result */ @SuppressWarnings("unchecked") - public final Try catching(Class throwableType, Function recoveryFn) { + public final Try catching(Class throwableType, + Function recoveryFn) { return catching(throwableType::isInstance, t -> recoveryFn.apply((S) t)); } @@ -54,8 +53,8 @@ public final Try catching(Class throwableType, Function catching(Function predicate, - Function recoveryFn) { + public final Try catching(Function predicate, + Function recoveryFn) { return match(t -> predicate.apply(t) ? success(recoveryFn.apply(t)) : failure(t), Try::success); } @@ -72,10 +71,13 @@ public final Try catching(Function predicate * @return the same {@link Try} instance if runnable completes successfully; otherwise, a {@link Try} conforming to * rules above */ - public final Try ensuring(CheckedRunnable runnable) { - return match(t -> peek2(t::addSuppressed, __ -> {}, trying(runnable)) - .biMapL(constantly(t)) - .flatMap(constantly(failure(t))), + public final Try ensuring(CheckedRunnable runnable) { + return match(t -> trying(runnable) + .>fmap(constantly(failure(t))) + .recover(t2 -> { + t.addSuppressed(t2); + return failure(t); + }), a -> trying(runnable).fmap(constantly(a))); } @@ -86,7 +88,7 @@ public final Try ensuring(CheckedRunnable runnable) { * @param fn the function mapping the potential {@link Throwable} T to A * @return a success value */ - public final A recover(Function fn) { + public final A recover(Function fn) { return match(fn, id()); } @@ -97,7 +99,7 @@ public final A recover(Function fn) { * @param fn the function mapping the potential A to T * @return a failure value */ - public final T forfeit(Function fn) { + public final Throwable forfeit(Function fn) { return match(id(), fn); } @@ -105,9 +107,8 @@ public final T forfeit(Function fn) { * If this is a success value, return it. Otherwise, rethrow the captured failure. * * @return possibly the success value - * @throws T the possible failure */ - public abstract A orThrow() throws T; + public abstract A orThrow(); /** * If this is a success, wrap the value in a {@link Maybe#just} and return it. Otherwise, return {@link @@ -125,7 +126,7 @@ public final Maybe toMaybe() { * * @return {@link Either} the success value or the {@link Throwable} */ - public final Either toEither() { + public final Either toEither() { return toEither(id()); } @@ -137,7 +138,7 @@ public final Either toEither() { * @param the {@link Either} left parameter type * @return {@link Either} the success value or the mapped left value */ - public final Either toEither(Function fn) { + public final Either toEither(Function fn) { return match(fn.andThen(Either::left), Either::right); } @@ -145,7 +146,7 @@ public final Either toEither(Function fn) { * {@inheritDoc} */ @Override - public Try fmap(Function fn) { + public Try fmap(Function fn) { return Monad.super.fmap(fn).coerce(); } @@ -153,7 +154,7 @@ public Try fmap(Function fn) { * {@inheritDoc} */ @Override - public Try flatMap(Function>> f) { + public Try flatMap(Function>> f) { return match(Try::failure, a -> f.apply(a).coerce()); } @@ -161,7 +162,7 @@ public Try flatMap(Function>> * {@inheritDoc} */ @Override - public Try pure(B b) { + public Try pure(B b) { return success(b); } @@ -169,13 +170,13 @@ public Try pure(B b) { * {@inheritDoc} */ @Override - public Try zip(Applicative, Try> appFn) { + public Try zip(Applicative, Try> appFn) { return Monad.super.zip(appFn).coerce(); } @Override - public Lazy> lazyZip( - Lazy, Try>> lazyAppFn) { + public Lazy> lazyZip( + Lazy, Try>> lazyAppFn) { return match(f -> lazy(failure(f)), s -> lazyAppFn.fmap(tryF -> tryF.fmap(f -> f.apply(s)).coerce())); } @@ -184,7 +185,7 @@ public Lazy> lazyZip( * {@inheritDoc} */ @Override - public Try discardL(Applicative> appB) { + public Try discardL(Applicative> appB) { return Monad.super.discardL(appB).coerce(); } @@ -192,7 +193,7 @@ public Try discardL(Applicative> appB) { * {@inheritDoc} */ @Override - public Try discardR(Applicative> appB) { + public Try discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } @@ -201,48 +202,22 @@ public Try discardR(Applicative> appB) { */ @Override @SuppressWarnings("unchecked") - public , TravB extends Traversable>, + public , TravB extends Traversable>, AppB extends Applicative, AppTrav extends Applicative> AppTrav traverse(Function fn, Function pure) { return match(t -> pure.apply((TravB) failure(t)), - a -> fn.apply(a).>fmap(Try::success).fmap(Applicative::coerce).coerce()); - } - - /** - * {@inheritDoc} - */ - @Override - public Try biMap(Function lFn, - Function rFn) { - return match(t -> failure(lFn.apply(t)), a -> success(rFn.apply(a))); - } - - /** - * {@inheritDoc} - */ - @Override - public Try biMapL(Function fn) { - return (Try) BoundedBifunctor.super.biMapL(fn); - } - - /** - * {@inheritDoc} - */ - @Override - public Try biMapR(Function fn) { - return (Try) BoundedBifunctor.super.biMapR(fn); + a -> fn.apply(a).fmap(Try::success).fmap(Applicative::coerce).coerce()); } /** * Static factory method for creating a success value. * * @param a the wrapped value - * @param the failure parameter type * @param the success parameter type * @return a success value of a */ - public static Try success(A a) { + public static Try success(A a) { return new Success<>(a); } @@ -254,7 +229,7 @@ public static Try success(A a) { * @param the success parameter type * @return a failure value of t */ - public static Try failure(T t) { + public static Try failure(T t) { return new Failure<>(t); } @@ -266,12 +241,11 @@ public static Try failure(T t) { * @param the possible success type * @return a new {@link Try} around either a successful A result or the thrown {@link Throwable} */ - @SuppressWarnings("unchecked") - public static Try trying(CheckedSupplier supplier) { + public static Try trying(CheckedSupplier supplier) { try { return success(supplier.get()); } catch (Throwable t) { - return failure((T) t); + return failure(t); } } @@ -279,10 +253,9 @@ public static Try trying(CheckedSupplier su * Execute runnable, returning a success {@link Unit} or a failure of the thrown {@link Throwable}. * * @param runnable the runnable - * @param the possible {@link Throwable} type * @return a new {@link Try} around either a successful {@link Unit} result or the thrown {@link Throwable} */ - public static Try trying(CheckedRunnable runnable) { + public static Try trying(CheckedRunnable runnable) { return trying(() -> { runnable.run(); return UNIT; @@ -317,12 +290,12 @@ public static Try trying(CheckedRunnable runna * @return a {@link Try} representing the result of the function's application to the resource */ @SuppressWarnings("try") - public static Try withResources( + public static Try withResources( CheckedSupplier aSupplier, - CheckedFn1> fn) { + CheckedFn1> fn) { return trying(() -> { try (A resource = aSupplier.get()) { - return fn.apply(resource).biMap(upcast(), upcast()); + return fn.apply(resource).fmap(upcast()); } }).flatMap(id()); } @@ -339,10 +312,10 @@ public static Try withResources( * @param the function return type * @return a {@link Try} representing the result of the function's application to the dependent resource */ - public static Try withResources( + public static Try withResources( CheckedSupplier aSupplier, CheckedFn1 bFn, - CheckedFn1> fn) { + CheckedFn1> fn) { return withResources(aSupplier, a -> withResources(() -> bFn.apply(a), fn::apply)); } @@ -361,28 +334,28 @@ public static Try the function return type * @return a {@link Try} representing the result of the function's application to the final dependent resource */ - public static Try withResources( + public static Try withResources( CheckedSupplier aSupplier, CheckedFn1 bFn, CheckedFn1 cFn, - CheckedFn1> fn) { + CheckedFn1> fn) { return withResources(aSupplier, bFn, b -> withResources(() -> cFn.apply(b), fn::apply)); } - private static final class Failure extends Try { - private final T t; + private static final class Failure extends Try { + private final Throwable t; - private Failure(T t) { + private Failure(Throwable t) { this.t = t; } @Override - public A orThrow() throws T { - throw t; + public A orThrow() { + throw Runtime.throwChecked(t); } @Override - public R match(Function aFn, Function bFn) { + public R match(Function aFn, Function bFn) { return aFn.apply(t); } @@ -404,7 +377,7 @@ public String toString() { } } - private static final class Success extends Try { + private static final class Success extends Try { private final A a; private Success(A a) { @@ -412,12 +385,12 @@ private Success(A a) { } @Override - public A orThrow() throws T { + public A orThrow() { return a; } @Override - public R match(Function aFn, Function bFn) { + public R match(Function aFn, Function bFn) { return bFn.apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java index 1546e811b..5ba88fd93 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java @@ -1,6 +1,9 @@ package com.jnape.palatable.lambda.functions.specialized.checked; -class Runtime { +public final class Runtime { + + private Runtime() { + } @SuppressWarnings("unchecked") public static RuntimeException throwChecked(Throwable t) throws T { diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java index f7b622bb8..510c95d91 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.adt.hlist.Tuple3; import java.time.Duration; @@ -13,12 +14,14 @@ import java.util.Set; import java.util.function.Supplier; +import static com.jnape.palatable.lambda.adt.Try.failure; import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; import static com.jnape.palatable.lambda.functions.builtin.fn2.Filter.filter; import static com.jnape.palatable.lambda.functions.builtin.fn2.GTE.gte; import static com.jnape.palatable.lambda.functions.builtin.fn2.LT.lt; import static com.jnape.palatable.lambda.functions.builtin.fn2.LTE.lte; +import static com.jnape.palatable.lambda.monad.Monad.join; import static com.jnape.palatable.lambda.semigroup.builtin.Max.max; import static java.lang.Thread.sleep; import static java.util.Collections.emptyList; @@ -58,14 +61,17 @@ private void awaitNextTimeSlice() { private void awaitNextTimeSliceForRateLimit(Tuple3> rateLimit) { while (rateLimitExhaustedInTimeSlice(rateLimit)) { - trying(() -> sleep(0)).biMapL(IterationInterruptedException::new).orThrow(); + join(trying(() -> sleep(0)) + .fmap(Try::success) + .catching(InterruptedException.class, t -> failure(new IterationInterruptedException(t)))) + .orThrow(); } } private boolean rateLimitExhaustedInTimeSlice(Tuple3> rateLimit) { List timeSlicesForRateLimit = timeSlicesByRateLimit.getOrDefault(rateLimit, emptyList()); return rateLimit.into((limit, duration, instantSupplier) -> { - Instant timeSliceEnd = instantSupplier.get(); + Instant timeSliceEnd = instantSupplier.get(); Instant previousTimeSliceEnd = timeSliceEnd.minus(duration); timeSlicesForRateLimit.removeIf(lt(previousTimeSliceEnd)); return max(0L, limit - size(filter(mark -> lte(mark, previousTimeSliceEnd) && gte(mark, timeSliceEnd), timeSlicesForRateLimit))) == 0; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index 57b1696f8..aca7d039d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -44,13 +44,13 @@ public class TryTest { @Rule public ExpectedException thrown = ExpectedException.none(); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) - public Subjects> testSubject() { + public Subjects> testSubject() { return subjects(failure(new IllegalStateException()), success(1)); } @Test public void catchingWithGenericPredicate() { - Try caught = Try.failure(new RuntimeException()) + Try caught = Try.failure(new RuntimeException()) .catching(__ -> false, r -> "caught first") .catching(__ -> true, r -> "caught second"); @@ -59,7 +59,7 @@ public void catchingWithGenericPredicate() { @Test public void catchingIsANoOpForSuccess() { - Try caught = Try.success("success") + Try caught = success("success") .catching(__ -> true, __ -> "caught"); assertEquals(success("success"), caught); @@ -67,7 +67,7 @@ public void catchingIsANoOpForSuccess() { @Test public void firstMatchingCatchBlockWins() { - Try caught = Try.failure(new IllegalStateException()) + Try caught = Try.failure(new IllegalStateException()) .catching(__ -> true, __ -> "first") .catching(__ -> true, __ -> "second"); @@ -76,7 +76,7 @@ public void firstMatchingCatchBlockWins() { @Test public void catchBasedOnExceptionType() { - Try caught = Try.failure(new IllegalStateException()) + Try caught = Try.failure(new IllegalStateException()) .catching(IllegalArgumentException.class, __ -> "illegal argument exception") .catching(IllegalStateException.class, __ -> "illegal state exception") .catching(RuntimeException.class, __ -> "runtime exception"); @@ -87,7 +87,7 @@ public void catchBasedOnExceptionType() { @Test public void ensureIfSuccess() { AtomicInteger invocations = new AtomicInteger(0); - Try.success(1).ensuring((invocations::incrementAndGet)); + success(1).ensuring((invocations::incrementAndGet)); assertEquals(1, invocations.get()); } @@ -101,9 +101,9 @@ public void ensureIfFailure() { @Test public void exceptionThrownInEnsuringBlockIsCaught() { IllegalStateException expected = new IllegalStateException(); - assertEquals(Try.failure(expected), Try.success(1).ensuring(() -> {throw expected;})); + assertEquals(Try.failure(expected), success(1).ensuring(() -> {throw expected;})); - Either actual = Try.failure(new IllegalArgumentException()) + Either actual = Try.failure(new IllegalArgumentException()) .ensuring(() -> { throw expected;}) .toEither(); assertThat(actual, isLeftThat(instanceOf(IllegalArgumentException.class))); @@ -114,12 +114,12 @@ public void exceptionThrownInEnsuringBlockIsCaught() { public void forfeitEnsuresFailure() { IllegalStateException expected = new IllegalStateException(); assertEquals(expected, Try.failure(expected).forfeit(__ -> new IllegalArgumentException())); - assertEquals(expected, Try.success(1).forfeit(__ -> expected)); + assertEquals(expected, Try.success(1).forfeit(__ -> expected)); } @Test public void recoverEnsuresSuccess() { - assertEquals((Integer) 1, Try.success(1).recover(constantly(1))); + assertEquals((Integer) 1, Try.success(1).recover(constantly(1))); assertEquals((Integer) 1, Try.failure(new IllegalArgumentException()).recover(constantly(1))); } @@ -134,13 +134,13 @@ public void orThrow() throws Throwable { @Test public void toMaybe() { - assertEquals(just("foo"), Try.success("foo").toMaybe()); + assertEquals(just("foo"), success("foo").toMaybe()); assertEquals(nothing(), Try.failure(new IllegalStateException()).toMaybe()); } @Test public void toEither() { - assertEquals(right("foo"), Try.success("foo").toEither()); + assertEquals(right("foo"), success("foo").toEither()); IllegalStateException exception = new IllegalStateException(); assertEquals(left(exception), Try.failure(exception).toEither()); @@ -148,7 +148,7 @@ public void toEither() { @Test public void toEitherWithLeftMappingFunction() { - assertEquals(right(1), Try.success(1).toEither(__ -> "fail")); + assertEquals(right(1), success(1).toEither(__ -> "fail")); assertEquals(left("fail"), Try.failure(new IllegalStateException("fail")).toEither(Throwable::getMessage)); } @@ -163,13 +163,13 @@ public void tryingCatchesAnyThrowableThrownDuringEvaluation() { @Test public void withResourcesCleansUpAutoCloseableInSuccessCase() { AtomicBoolean closed = new AtomicBoolean(false); - assertEquals(Try.success(1), Try.withResources(() -> () -> closed.set(true), resource -> success(1))); + assertEquals(success(1), Try.withResources(() -> () -> closed.set(true), resource -> success(1))); assertTrue(closed.get()); } @Test public void withResourcesCleansUpAutoCloseableInFailureCase() { - AtomicBoolean closed = new AtomicBoolean(false); + AtomicBoolean closed = new AtomicBoolean(false); RuntimeException exception = new RuntimeException(); assertEquals(Try.failure(exception), Try.withResources(() -> () -> closed.set(true), resource -> { throw exception; })); @@ -191,11 +191,11 @@ public void withResourcesExposesResourceCloseFailure() { @Test public void withResourcesPreservesSuppressedExceptionThrownDuringClose() { - RuntimeException rootException = new RuntimeException(); - IOException nestedIOException = new IOException(); - Try failure = Try.withResources(() -> () -> { throw nestedIOException; }, - resource -> { throw rootException; }); - Exception thrown = failure.recover(id()); + RuntimeException rootException = new RuntimeException(); + IOException nestedIOException = new IOException(); + Try failure = Try.withResources(() -> () -> { throw nestedIOException; }, + resource -> { throw rootException; }); + Throwable thrown = failure.recover(id()); assertEquals(thrown, rootException); assertArrayEquals(new Throwable[]{nestedIOException}, thrown.getSuppressed()); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java index 0459a8be1..b37527919 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java @@ -1,6 +1,5 @@ package com.jnape.palatable.lambda.functions.builtin.fn4; -import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.iteration.IterationInterruptedException; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -17,8 +16,10 @@ import java.time.Duration; import java.util.concurrent.CountDownLatch; +import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.functions.builtin.fn4.RateLimit.rateLimit; +import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable.checked; import static java.time.Clock.systemUTC; import static java.time.Duration.ZERO; import static java.util.Arrays.asList; @@ -55,18 +56,17 @@ public void zeroDurationJustIteratesElements() { @Test public void limitPerDurationIsHonoredAccordingToClock() { Duration duration = Duration.ofMillis(10); - long limit = 2L; + long limit = 2L; assertThat(rateLimit(clock::instant, limit, duration, asList(1, 2, 3, 4)), iteratesAccordingToRateLimit(limit, duration, asList(1, 2, 3, 4), clock)); } @Test(timeout = 100, expected = IterationInterruptedException.class) public void rateLimitingDelayIsInterruptible() throws InterruptedException { - Thread testThread = Thread.currentThread(); - CountDownLatch latch = new CountDownLatch(1); + Thread testThread = Thread.currentThread(); + CountDownLatch latch = new CountDownLatch(1); new Thread(() -> { - Try.trying(latch::await).biMapL(AssertionError::new) - .orThrow(); + trying(checked(latch::await)).orThrow(); testThread.interrupt(); }) {{ start(); From f240f84ed122852ede134975c7857b92b8917006 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 5 May 2019 21:35:59 -0500 Subject: [PATCH 142/348] Try#orThrow can declare checked exceptions for catching purposes --- CHANGELOG.md | 5 +++-- .../java/com/jnape/palatable/lambda/adt/Try.java | 2 +- .../com/jnape/palatable/lambda/adt/TryTest.java | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cda581167..834bb104f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,9 @@ might need to be reworked, and subtyping is obviously no longer supported. - ***Breaking Change***: `Strong` is now called `Cartesian` to better reflect the type of strength - ***Breaking Change***: new Optic type hierarchy more faithfully encodes profunctor constraints on optics, new `Optic` type is now the supertype of `Lens` and `Iso`, and `lens` package has been moved to `optics` -- ***Breaking Change***: Try and Either no longer preserve `Throwable` type since it was inherently not type-safe - anyway; Try is therefore no longer a `Bifunctor` +- ***Breaking Change***: `Try` and `Either` no longer preserve `Throwable` type since it was inherently not type-safe + anyway; Try is therefore no longer a `Bifunctor`, and `orThrow` can be used to declare checked + exceptions that could be caught by corresponding catch blocks - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index fddedbb37..165c6333c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -108,7 +108,7 @@ public final Throwable forfeit(Function fn) { * * @return possibly the success value */ - public abstract A orThrow(); + public abstract A orThrow() throws T; /** * If this is a success, wrap the value in a {@link Maybe#just} and return it. Otherwise, return {@link diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index aca7d039d..77425e391 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -36,6 +36,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static testsupport.matchers.LeftMatcher.isLeftThat; @RunWith(Traits.class) @@ -219,4 +220,17 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void orThrowCanStillThrowCheckedExceptions() { + try { + Try.trying(() -> { + throw new RuntimeException(); + }).orThrow(); + fail("Expected RuntimeException to be thrown, but nothing was"); + } catch (IOException ioException) { + fail("Expected thrown exception to not be IOException, but merely proving it can still be caught"); + } catch (Exception expected) { + } + } } \ No newline at end of file From 91d414a667c4fabc726d4aaefac2fa12110b859b Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 6 May 2019 18:50:38 -0500 Subject: [PATCH 143/348] Adding checkedApply to all function variants to support implicit throws --- CHANGELOG.md | 5 +++- .../jnape/palatable/lambda/adt/Either.java | 4 +-- .../com/jnape/palatable/lambda/adt/Try.java | 8 ++++-- .../palatable/lambda/functions/Effect.java | 17 +++++++++++ .../jnape/palatable/lambda/functions/Fn0.java | 18 ++++++++---- .../jnape/palatable/lambda/functions/Fn1.java | 19 +++++++++++-- .../jnape/palatable/lambda/functions/Fn2.java | 19 ++++++++++++- .../jnape/palatable/lambda/functions/Fn3.java | 19 ++++++++++++- .../jnape/palatable/lambda/functions/Fn4.java | 19 ++++++++++++- .../jnape/palatable/lambda/functions/Fn5.java | 20 ++++++++++++- .../jnape/palatable/lambda/functions/Fn6.java | 20 ++++++++++++- .../jnape/palatable/lambda/functions/Fn7.java | 19 ++++++++++++- .../jnape/palatable/lambda/functions/Fn8.java | 19 ++++++++++++- .../functions/builtin/fn1/CatMaybes.java | 2 +- .../functions/builtin/fn1/Coalesce.java | 2 +- .../functions/builtin/fn1/Constantly.java | 2 +- .../lambda/functions/builtin/fn1/Cycle.java | 2 +- .../functions/builtin/fn1/Distinct.java | 2 +- .../functions/builtin/fn1/Downcast.java | 2 +- .../lambda/functions/builtin/fn1/Empty.java | 2 +- .../lambda/functions/builtin/fn1/Flatten.java | 2 +- .../lambda/functions/builtin/fn1/Force.java | 2 +- .../lambda/functions/builtin/fn1/Head.java | 2 +- .../lambda/functions/builtin/fn1/Id.java | 2 +- .../lambda/functions/builtin/fn1/Init.java | 2 +- .../lambda/functions/builtin/fn1/Inits.java | 2 +- .../lambda/functions/builtin/fn1/Last.java | 2 +- .../functions/builtin/fn1/Magnetize.java | 2 +- .../lambda/functions/builtin/fn1/Not.java | 2 +- .../functions/builtin/fn1/Occurrences.java | 2 +- .../lambda/functions/builtin/fn1/Repeat.java | 2 +- .../lambda/functions/builtin/fn1/Reverse.java | 2 +- .../lambda/functions/builtin/fn1/Size.java | 2 +- .../lambda/functions/builtin/fn1/Sort.java | 2 +- .../lambda/functions/builtin/fn1/Tail.java | 2 +- .../lambda/functions/builtin/fn1/Tails.java | 2 +- .../lambda/functions/builtin/fn1/Uncons.java | 2 +- .../lambda/functions/builtin/fn1/Upcast.java | 2 +- .../lambda/functions/builtin/fn2/All.java | 2 +- .../lambda/functions/builtin/fn2/Alter.java | 2 +- .../lambda/functions/builtin/fn2/Any.java | 2 +- .../lambda/functions/builtin/fn2/Both.java | 8 +++--- .../builtin/fn2/CartesianProduct.java | 4 +-- .../lambda/functions/builtin/fn2/CmpEq.java | 2 +- .../lambda/functions/builtin/fn2/Cons.java | 2 +- .../functions/builtin/fn2/Difference.java | 2 +- .../lambda/functions/builtin/fn2/Drop.java | 2 +- .../functions/builtin/fn2/DropWhile.java | 2 +- .../lambda/functions/builtin/fn2/Eq.java | 2 +- .../lambda/functions/builtin/fn2/Filter.java | 2 +- .../lambda/functions/builtin/fn2/Find.java | 2 +- .../lambda/functions/builtin/fn2/GT.java | 2 +- .../lambda/functions/builtin/fn2/GTE.java | 2 +- .../lambda/functions/builtin/fn2/GroupBy.java | 4 +-- .../functions/builtin/fn2/InGroupsOf.java | 2 +- .../functions/builtin/fn2/Intersection.java | 2 +- .../functions/builtin/fn2/Intersperse.java | 2 +- .../lambda/functions/builtin/fn2/Into.java | 4 +-- .../lambda/functions/builtin/fn2/Into1.java | 4 +-- .../lambda/functions/builtin/fn2/Into3.java | 4 +-- .../lambda/functions/builtin/fn2/Into4.java | 5 ++-- .../lambda/functions/builtin/fn2/Into5.java | 6 ++-- .../lambda/functions/builtin/fn2/Into6.java | 6 ++-- .../lambda/functions/builtin/fn2/Into7.java | 7 +++-- .../lambda/functions/builtin/fn2/Into8.java | 2 +- .../lambda/functions/builtin/fn2/Iterate.java | 2 +- .../lambda/functions/builtin/fn2/LT.java | 2 +- .../lambda/functions/builtin/fn2/LTE.java | 2 +- .../lambda/functions/builtin/fn2/LazyRec.java | 2 +- .../functions/builtin/fn2/MagnetizeBy.java | 3 +- .../lambda/functions/builtin/fn2/Map.java | 2 +- .../functions/builtin/fn2/Partial2.java | 4 +-- .../functions/builtin/fn2/Partial3.java | 4 +-- .../functions/builtin/fn2/Partition.java | 6 ++-- .../lambda/functions/builtin/fn2/Peek.java | 4 +-- .../lambda/functions/builtin/fn2/Peek2.java | 2 +- .../functions/builtin/fn2/PrependAll.java | 2 +- .../functions/builtin/fn2/ReduceLeft.java | 2 +- .../functions/builtin/fn2/ReduceRight.java | 2 +- .../functions/builtin/fn2/Replicate.java | 2 +- .../functions/builtin/fn2/Sequence.java | 2 +- .../lambda/functions/builtin/fn2/Slide.java | 2 +- .../lambda/functions/builtin/fn2/Snoc.java | 2 +- .../lambda/functions/builtin/fn2/SortBy.java | 4 +-- .../functions/builtin/fn2/SortWith.java | 2 +- .../lambda/functions/builtin/fn2/Span.java | 3 +- .../lambda/functions/builtin/fn2/Take.java | 2 +- .../functions/builtin/fn2/TakeWhile.java | 2 +- .../lambda/functions/builtin/fn2/ToArray.java | 2 +- .../functions/builtin/fn2/ToCollection.java | 2 +- .../lambda/functions/builtin/fn2/ToMap.java | 2 +- .../lambda/functions/builtin/fn2/Tupler2.java | 2 +- .../lambda/functions/builtin/fn2/Unfoldr.java | 2 +- .../lambda/functions/builtin/fn2/Zip.java | 2 +- .../lambda/functions/builtin/fn3/Between.java | 2 +- .../lambda/functions/builtin/fn3/Clamp.java | 2 +- .../lambda/functions/builtin/fn3/CmpEqBy.java | 2 +- .../functions/builtin/fn3/FoldLeft.java | 2 +- .../functions/builtin/fn3/FoldRight.java | 3 +- .../lambda/functions/builtin/fn3/GTBy.java | 4 +-- .../lambda/functions/builtin/fn3/GTEBy.java | 2 +- .../lambda/functions/builtin/fn3/LTBy.java | 2 +- .../lambda/functions/builtin/fn3/LTEBy.java | 2 +- .../lambda/functions/builtin/fn3/LiftA2.java | 2 +- .../functions/builtin/fn3/ScanLeft.java | 2 +- .../lambda/functions/builtin/fn3/Times.java | 2 +- .../lambda/functions/builtin/fn3/ZipWith.java | 3 +- .../functions/builtin/fn4/IfThenElse.java | 4 +-- .../lambda/functions/builtin/fn4/LiftA3.java | 2 +- .../functions/builtin/fn4/RateLimit.java | 2 +- .../lambda/functions/builtin/fn5/LiftA4.java | 2 +- .../lambda/functions/builtin/fn6/LiftA5.java | 2 +- .../lambda/functions/builtin/fn7/LiftA6.java | 4 +-- .../lambda/functions/builtin/fn8/LiftA7.java | 4 +-- .../functions/recursion/Trampoline.java | 2 +- .../specialized/BiMonoidFactory.java | 23 ++++++++++++--- .../specialized/BiSemigroupFactory.java | 17 +++++++---- .../functions/specialized/MonoidFactory.java | 12 +++++++- .../lambda/functions/specialized/Noop.java | 2 +- .../lambda/functions/specialized/Pure.java | 12 +++++++- .../specialized/SemigroupFactory.java | 11 ++++++-- .../specialized/checked/CheckedEffect.java | 22 +++++---------- .../specialized/checked/CheckedFn1.java | 28 +++++++------------ .../jnape/palatable/lambda/monoid/Monoid.java | 4 +-- .../lambda/monoid/builtin/AddAll.java | 6 ++-- .../palatable/lambda/monoid/builtin/And.java | 2 +- .../lambda/monoid/builtin/Collapse.java | 7 +++-- .../lambda/monoid/builtin/Compose.java | 2 +- .../lambda/monoid/builtin/Concat.java | 2 +- .../palatable/lambda/monoid/builtin/Endo.java | 10 +++---- .../lambda/monoid/builtin/First.java | 2 +- .../palatable/lambda/monoid/builtin/Join.java | 2 +- .../palatable/lambda/monoid/builtin/Last.java | 2 +- .../lambda/monoid/builtin/LeftAll.java | 2 +- .../lambda/monoid/builtin/LeftAny.java | 4 +-- .../lambda/monoid/builtin/Merge.java | 4 +-- .../lambda/monoid/builtin/MergeMaps.java | 2 +- .../palatable/lambda/monoid/builtin/Or.java | 4 +-- .../lambda/monoid/builtin/Present.java | 2 +- .../lambda/monoid/builtin/PutAll.java | 2 +- .../lambda/monoid/builtin/RightAll.java | 2 +- .../lambda/monoid/builtin/RightAny.java | 4 +-- .../lambda/monoid/builtin/RunAll.java | 4 +-- .../lambda/monoid/builtin/Union.java | 2 +- .../palatable/lambda/monoid/builtin/Xor.java | 2 +- .../lambda/optics/functions/Matching.java | 2 +- .../lambda/optics/functions/Over.java | 6 ++-- .../lambda/optics/functions/Pre.java | 4 +-- .../palatable/lambda/optics/functions/Re.java | 2 +- .../lambda/optics/functions/Set.java | 2 +- .../lambda/optics/functions/Under.java | 6 ++-- .../lambda/optics/functions/View.java | 2 +- .../lambda/semigroup/builtin/Absent.java | 2 +- .../lambda/semigroup/builtin/Collapse.java | 4 +-- .../lambda/semigroup/builtin/Compose.java | 2 +- .../lambda/semigroup/builtin/LeftAll.java | 4 +-- .../lambda/semigroup/builtin/LeftAny.java | 2 +- .../lambda/semigroup/builtin/Max.java | 2 +- .../lambda/semigroup/builtin/MaxBy.java | 4 +-- .../lambda/semigroup/builtin/Merge.java | 2 +- .../lambda/semigroup/builtin/Min.java | 2 +- .../lambda/semigroup/builtin/MinBy.java | 4 +-- .../lambda/semigroup/builtin/RightAll.java | 4 +-- .../lambda/semigroup/builtin/RightAny.java | 4 +-- .../lambda/semigroup/builtin/RunAll.java | 4 +-- .../lambda/functions/EffectTest.java | 10 +++---- .../lambda/functor/builtin/LazyTest.java | 2 +- .../com/jnape/palatable/lambda/io/IOTest.java | 4 +-- 168 files changed, 473 insertions(+), 273 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 834bb104f..eb5b0499e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,10 @@ might need to be reworked, and subtyping is obviously no longer supported. type is now the supertype of `Lens` and `Iso`, and `lens` package has been moved to `optics` - ***Breaking Change***: `Try` and `Either` no longer preserve `Throwable` type since it was inherently not type-safe anyway; Try is therefore no longer a `Bifunctor`, and `orThrow` can be used to declare checked - exceptions that could be caught by corresponding catch blocks + exceptions that could be caught by corresponding catch blocks +- ***Breaking Change***: All `Fn*` types target methods now support throwing `Throwable`; `apply` is now defaulted and + will simply bypass javac to throw checked exceptions as if they were unchecked. This allows all + checked variants to be eliminated - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ### Added 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 bda1b4fa2..e248eef92 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -2,9 +2,9 @@ import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek2; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1; import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable; import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functor.Applicative; @@ -83,7 +83,7 @@ public final L forfeit(Function forfeitFn) { * @throws T the result of applying the wrapped left value to throwableFn, if this is a left */ public final R orThrow(Function throwableFn) throws T { - return match((CheckedFn1) l -> { + return match((Fn1) l -> { throw throwableFn.apply(l); }, id()); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index 165c6333c..fe1581307 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -292,7 +292,7 @@ public static Try trying(CheckedRunnable runnable) { @SuppressWarnings("try") public static Try withResources( CheckedSupplier aSupplier, - CheckedFn1> fn) { + CheckedFn1> fn) { return trying(() -> { try (A resource = aSupplier.get()) { return fn.apply(resource).fmap(upcast()); @@ -316,7 +316,8 @@ public static Try withR CheckedSupplier aSupplier, CheckedFn1 bFn, CheckedFn1> fn) { - return withResources(aSupplier, a -> withResources(() -> bFn.apply(a), fn::apply)); + CheckedFn1> checkedFn = a -> withResources(() -> bFn.apply(a), fn::apply); + return withResources(aSupplier, checkedFn); } /** @@ -339,7 +340,8 @@ public static bFn, CheckedFn1 cFn, CheckedFn1> fn) { - return withResources(aSupplier, bFn, b -> withResources(() -> cFn.apply(b), fn::apply)); + CheckedFn1> checkedFn = b -> withResources(() -> cFn.apply(b), fn::apply); + return withResources(aSupplier, bFn, checkedFn); } private static final class Failure extends Try { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 0074cdd42..3115bef10 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.io.IO; @@ -20,11 +21,27 @@ @FunctionalInterface public interface Effect extends Fn1>, Consumer { + void checkedAccept(A a) throws Throwable; + + @Override + default void accept(A a) { + try { + checkedAccept(a); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + @Override default IO apply(A a) { return io(() -> accept(a)); } + @Override + default IO checkedApply(A a) throws Throwable { + return io(() -> accept(a)); + } + @Override default Effect diMapL(Function fn) { return effect(Fn1.super.diMapL(fn)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index a1c67f5cc..902bcd940 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -21,17 +21,23 @@ @FunctionalInterface public interface Fn0 extends Fn1, Supplier, Callable { - A apply(); + A checkedApply() throws Throwable; /** - * Invoke this function with {@link Unit}. + * Convenience method for applying this {@link Fn0} without providing an explicit {@link Unit}. * - * @param unit the only allowed input - * @return the result value + * @return the result + */ + default A apply() { + return apply(UNIT); + } + + /** + * {@inheritDoc} */ @Override - default A apply(Unit unit) { - return apply(); + default A checkedApply(Unit unit) throws Throwable { + return checkedApply(); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 566ac93db..8704f92f4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cartesian; import com.jnape.palatable.lambda.functor.Cocartesian; @@ -30,12 +31,26 @@ public interface Fn1 extends Function { /** - * Invoke this function with the given argument. + * Invoke this function explosively with the given argument. * * @param a the argument * @return the result of the function application */ - B apply(A a); + default B apply(A a) { + try { + return checkedApply(a); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + + /** + * Invoke this function with the given argument, potentially throwing any {@link Throwable}. + * + * @param a the argument + * @return the result of the function application + */ + B checkedApply(A a) throws Throwable; /** * Convert this {@link Fn1} to an {@link Fn0} by supplying an argument to this function. Useful for fixing an diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index 1386ae11e..cbe3a0929 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -23,6 +24,8 @@ @FunctionalInterface public interface Fn2 extends Fn1> { + C checkedApply(A a, B b) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -30,7 +33,21 @@ public interface Fn2 extends Fn1> { * @param b the second argument * @return the result of the function application */ - C apply(A a, B b); + default C apply(A a, B b) { + try { + return checkedApply(a, b); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 checkedApply(A a) throws Throwable { + return b -> checkedApply(a, b); + } /** * {@inheritDoc} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java index 9178520dc..84b46a1ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -21,6 +22,8 @@ @FunctionalInterface public interface Fn3 extends Fn2> { + D checkedApply(A a, B b, C c) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -29,7 +32,21 @@ public interface Fn3 extends Fn2> { * @param c the third argument * @return the result of the function application */ - D apply(A a, B b, C c); + default D apply(A a, B b, C c) { + try { + return checkedApply(a, b, c); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 checkedApply(A a, B b) throws Throwable { + return c -> checkedApply(a, b, c); + } /** * {@inheritDoc} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java index 4f9ea02de..e38856550 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -22,6 +23,8 @@ @FunctionalInterface public interface Fn4 extends Fn3> { + E checkedApply(A a, B b, C c, D d) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -31,7 +34,21 @@ public interface Fn4 extends Fn3> { * @param d the fourth argument * @return the result of the function application */ - E apply(A a, B b, C c, D d); + default E apply(A a, B b, C c, D d) { + try { + return checkedApply(a, b, c, d); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 checkedApply(A a, B b, C c) throws Throwable { + return d -> checkedApply(a, b, c, d); + } /** * {@inheritDoc} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java index f37f664e0..16bc6efa2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -23,6 +24,8 @@ @FunctionalInterface public interface Fn5 extends Fn4> { + F checkedApply(A a, B b, C c, D d, E e) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -33,7 +36,22 @@ public interface Fn5 extends Fn4> { * @param e the fifth argument * @return the result of the function application */ - F apply(A a, B b, C c, D d, E e); + default F apply(A a, B b, C c, D d, E e) { + try { + return checkedApply(a, b, c, d, e); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 checkedApply(A a, B b, C c, D d) throws Throwable { + return e -> checkedApply(a, b, c, d, e); + } /** * {@inheritDoc} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java index 69c6619cb..62917ce3a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -24,6 +25,8 @@ @FunctionalInterface public interface Fn6 extends Fn5> { + G checkedApply(A a, B b, C c, D d, E e, F f) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -35,7 +38,22 @@ public interface Fn6 extends Fn5> * @param f the sixth argument * @return the result of the function application */ - G apply(A a, B b, C c, D d, E e, F f); + default G apply(A a, B b, C c, D d, E e, F f) { + try { + return checkedApply(a, b, c, d, e, f); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 checkedApply(A a, B b, C c, D d, E e) throws Throwable { + return f -> checkedApply(a, b, c, d, e, f); + } /** * {@inheritDoc} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index 90feae545..2e18bef97 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -25,6 +26,8 @@ @FunctionalInterface public interface Fn7 extends Fn6> { + H checkedApply(A a, B b, C c, D d, E e, F f, G g) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -37,7 +40,21 @@ public interface Fn7 extends Fn6 checkedApply(A a, B b, C c, D d, E e, F f) throws Throwable { + return g -> checkedApply(a, b, c, d, e, f, g); + } /** * {@inheritDoc} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java index 9d5020687..07e8fb165 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import java.util.function.BiFunction; @@ -23,6 +24,8 @@ @FunctionalInterface public interface Fn8 extends Fn7> { + I checkedApply(A a, B b, C c, D d, E e, F f, G g, H h) throws Throwable; + /** * Invoke this function with the given arguments. * @@ -36,7 +39,21 @@ public interface Fn8 extends Fn7 checkedApply(A a, B b, C c, D d, E e, F f, G g) throws Throwable { + return h -> checkedApply(a, b, c, d, e, f, g, h); + } /** * Partially apply this function by taking its first argument. diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java index d74111ba3..9833e2a32 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/CatMaybes.java @@ -21,7 +21,7 @@ private CatMaybes() { } @Override - public Iterable apply(Iterable> maybes) { + public Iterable checkedApply(Iterable> maybes) { return flatten(map(m -> m.>fmap(Collections::singletonList) .orElse(Collections::emptyIterator), maybes)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java index ce9147028..3154e07ea 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Coalesce.java @@ -31,7 +31,7 @@ private Coalesce() { } @Override - public Either, Iterable> apply(Iterable> eithers) { + public Either, Iterable> checkedApply(Iterable> eithers) { return foldLeft((acc, e) -> acc .biMapL(ls -> e.match(Snoc.snoc().flip().apply(ls), constantly(ls))) .flatMap(rs -> e.biMap(Collections::singletonList, diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java index ed4d367b0..252eb53df 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Constantly.java @@ -17,7 +17,7 @@ private Constantly() { } @Override - public A apply(A a, B b) { + public A checkedApply(A a, B b) { return a; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java index df61e9fa0..2c39f4391 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java @@ -19,7 +19,7 @@ private Cycle() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return new CyclicIterable<>(as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java index 949c2c91e..aab8dfdb3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java @@ -15,7 +15,7 @@ private Distinct() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return new DistinctIterable<>(as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java index c7efde762..d9c0c3985 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Downcast.java @@ -17,7 +17,7 @@ private Downcast() { @Override @SuppressWarnings("unchecked") - public A apply(B b) { + public A checkedApply(B b) { return (A) b; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java index b8b0f656b..dca2ebe09 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java @@ -15,7 +15,7 @@ private Empty() { } @Override - public Boolean apply(Iterable as) { + public Boolean checkedApply(Iterable as) { return !as.iterator().hasNext(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java index ba05c771d..c1f8c0f6d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java @@ -16,7 +16,7 @@ private Flatten() { } @Override - public Iterable apply(Iterable> iterables) { + public Iterable checkedApply(Iterable> iterables) { return () -> new FlatteningIterator<>(iterables.iterator()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java index 84852199a..a198fc9ff 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java @@ -17,7 +17,7 @@ private Force() { @Override @SuppressWarnings("StatementWithEmptyBody") - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { for (A ignored : as) { } return as; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java index e6b2457e4..a7c2c16fd 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Head.java @@ -22,7 +22,7 @@ private Head() { } @Override - public Maybe apply(Iterable as) { + public Maybe checkedApply(Iterable as) { Iterator iterator = as.iterator(); return iterator.hasNext() ? just(iterator.next()) : nothing(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java index 62a5871ea..c2f8c06ee 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java @@ -15,7 +15,7 @@ private Id() { } @Override - public A apply(A a) { + public A checkedApply(A a) { return a; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java index 2162e65ee..bb75ad1b1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java @@ -17,7 +17,7 @@ private Init() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return () -> new InitIterator<>(as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java index cb6d7165c..e2b33f928 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java @@ -25,7 +25,7 @@ private Inits() { } @Override - public Iterable> apply(Iterable as) { + public Iterable> checkedApply(Iterable as) { return scanLeft(Snoc.snoc().flip().toBiFunction(), Collections::emptyIterator, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java index 9f49e95da..a71c1dda6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Last.java @@ -19,7 +19,7 @@ private Last() { } @Override - public Maybe apply(Iterable as) { + public Maybe checkedApply(Iterable as) { A last = null; for (A a : as) { last = a; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java index b25e3e32a..b50429e51 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java @@ -18,7 +18,7 @@ private Magnetize() { } @Override - public Iterable> apply(Iterable as) { + public Iterable> checkedApply(Iterable as) { return magnetizeBy(eq().toBiFunction(), as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java index a7b4956c6..74374b434 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java @@ -17,7 +17,7 @@ private Not() { } @Override - public Boolean apply(Function pred, A a) { + public Boolean checkedApply(Function pred, A a) { return !pred.apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java index af9e21f39..6fea549c8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Occurrences.java @@ -20,7 +20,7 @@ private Occurrences() { } @Override - public Map apply(Iterable as) { + public Map checkedApply(Iterable as) { return foldLeft((occurrences, a) -> { occurrences.put(a, occurrences.getOrDefault(a, 0L) + 1); return occurrences; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java index 68209c874..83c80e09a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java @@ -16,7 +16,7 @@ private Repeat() { } @Override - public Iterable apply(A a) { + public Iterable checkedApply(A a) { return () -> new RepetitiousIterator<>(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java index 3913da8f0..eaeecc014 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java @@ -17,7 +17,7 @@ private Reverse() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return new ReversingIterable<>(as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Size.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Size.java index 95dca3f36..061636248 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Size.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Size.java @@ -12,7 +12,7 @@ private Size() { } @Override - public Long apply(Iterable iterable) { + public Long checkedApply(Iterable iterable) { if (iterable instanceof Collection) return (long) ((Collection) iterable).size(); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java index 315b6780c..da00cfaaf 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Sort.java @@ -25,7 +25,7 @@ private Sort() { } @Override - public List apply(Iterable as) { + public List checkedApply(Iterable as) { return sortBy(id(), as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java index 930b4be95..9f776ccf0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tail.java @@ -18,7 +18,7 @@ private Tail() { } @Override - public Iterable apply(Iterable as) { + public Iterable checkedApply(Iterable as) { return drop(1, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java index cffe390d3..7179d1f31 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Tails.java @@ -28,7 +28,7 @@ private Tails() { } @Override - public Iterable> apply(Iterable as) { + public Iterable> checkedApply(Iterable as) { return snoc(emptyList(), zipWith((a, __) -> a, unfoldr(k -> just(tuple(drop(k, as), k + 1)), 0), as)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java index 27014940b..dc27d9bb3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Uncons.java @@ -22,7 +22,7 @@ private Uncons() { } @Override - public Maybe>> apply(Iterable as) { + public Maybe>> checkedApply(Iterable as) { return head(as).fmap(a -> tuple(a, tail(as))); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java index 89cfaa864..f4f187021 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Upcast.java @@ -28,7 +28,7 @@ private Upcast() { } @Override - public B apply(A a) { + public B checkedApply(A a) { return a; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java index 0019932b4..42a97c86f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java @@ -21,7 +21,7 @@ private All() { } @Override - public Boolean apply(Function predicate, Iterable as) { + public Boolean checkedApply(Function predicate, Iterable as) { for (A a : as) if (!predicate.apply(a)) return false; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java index b12160c1f..5eb0b2cc4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -21,7 +21,7 @@ private Alter() { } @Override - public IO apply(Effect effect, A a) { + public IO checkedApply(Effect effect, A a) { return effect.fmap(io -> io.fmap(constantly(a))).apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java index eacb359b3..048b79cef 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java @@ -21,7 +21,7 @@ private Any() { } @Override - public Boolean apply(Function predicate, Iterable as) { + public Boolean checkedApply(Function predicate, Iterable as) { for (A a : as) if (predicate.apply(a)) return true; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java index 0693437cd..fcd964c7c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java @@ -16,15 +16,15 @@ */ public final class Both implements Fn3, Function, A, Tuple2> { - private static final Both INSTANCE = new Both<>(); + private static final Both INSTANCE = new Both<>(); private Both() { } @Override - public Tuple2 apply(Function f, - Function g, - A a) { + public Tuple2 checkedApply(Function f, + Function g, + A a) { return Tuple2.fill(a).biMap(f, g); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java index e6663cfe3..2ef85c703 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java @@ -21,13 +21,13 @@ */ public final class CartesianProduct implements Fn2, Iterable, Iterable>> { - private static final CartesianProduct INSTANCE = new CartesianProduct<>(); + private static final CartesianProduct INSTANCE = new CartesianProduct<>(); private CartesianProduct() { } @Override - public Iterable> apply(Iterable as, Iterable bs) { + public Iterable> checkedApply(Iterable as, Iterable bs) { return () -> new CombinatorialIterator<>(as.iterator(), bs.iterator()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java index de9bd9e4e..3a91ade4c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CmpEq.java @@ -24,7 +24,7 @@ private CmpEq() { } @Override - public Boolean apply(A x, A y) { + public Boolean checkedApply(A x, A y) { return cmpEqBy(id(), x, y); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java index c69d18ddd..7ad8405a0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java @@ -17,7 +17,7 @@ private Cons() { } @Override - public Iterable apply(A a, Iterable as) { + public Iterable checkedApply(A a, Iterable as) { return () -> new ConsingIterator<>(a, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java index 384b62175..38735673c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Difference.java @@ -29,7 +29,7 @@ private Difference() { } @Override - public Iterable apply(Iterable xs, Iterable ys) { + public Iterable checkedApply(Iterable xs, Iterable ys) { return () -> { if (empty(xs)) return xs.iterator(); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java index 291324bdf..c975a0efb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java @@ -21,7 +21,7 @@ private Drop() { } @Override - public Iterable apply(Integer n, Iterable as) { + public Iterable checkedApply(Integer n, Iterable as) { return new DroppingIterable<>(n, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java index edd8e45fb..3585ef135 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java @@ -24,7 +24,7 @@ private DropWhile() { } @Override - public Iterable apply(Function predicate, Iterable as) { + public Iterable checkedApply(Function predicate, Iterable as) { return new PredicatedDroppingIterable<>(predicate, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java index 126d26072..e4c5aeda1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java @@ -16,7 +16,7 @@ private Eq() { } @Override - public Boolean apply(A x, A y) { + public Boolean checkedApply(A x, A y) { return x == null ? y == null : x.equals(y); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java index 8e208ac1b..f8954ae8e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java @@ -22,7 +22,7 @@ private Filter() { } @Override - public Iterable apply(Function predicate, Iterable as) { + public Iterable checkedApply(Function predicate, Iterable as) { return new FilteringIterable<>(predicate, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java index 2ddf0c8be..5539d71fc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java @@ -26,7 +26,7 @@ private Find() { } @Override - public Maybe apply(Function predicate, Iterable as) { + public Maybe checkedApply(Function predicate, Iterable as) { return head(dropWhile(not(predicate), as)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java index 7d99e7bc1..09d1be4ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GT.java @@ -23,7 +23,7 @@ private GT() { } @Override - public Boolean apply(A y, A x) { + public Boolean checkedApply(A y, A x) { return gtBy(id(), y, x); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java index 5304755de..89413cea6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GTE.java @@ -23,7 +23,7 @@ private GTE() { } @Override - public Boolean apply(A y, A x) { + public Boolean checkedApply(A y, A x) { return gteBy(id(), y, x); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java index 1e85a30ab..9cbc91ee8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java @@ -22,13 +22,13 @@ */ public final class GroupBy implements Fn2, Iterable, Map>> { - private static final GroupBy INSTANCE = new GroupBy<>(); + private static final GroupBy INSTANCE = new GroupBy<>(); private GroupBy() { } @Override - public Map> apply(Function keyFn, Iterable vs) { + public Map> checkedApply(Function keyFn, Iterable vs) { return foldLeft((m, v) -> { m.computeIfAbsent(keyFn.apply(v), __ -> new ArrayList<>()).add(v); return m; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java index 410e5745c..5270cf60f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java @@ -20,7 +20,7 @@ private InGroupsOf() { } @Override - public Iterable> apply(Integer k, Iterable as) { + public Iterable> checkedApply(Integer k, Iterable as) { return () -> new GroupingIterator<>(k, as.iterator()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java index 1a061a471..e7965d9ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java @@ -24,7 +24,7 @@ private Intersection() { } @Override - public Iterable apply(Iterable xs, Iterable ys) { + public Iterable checkedApply(Iterable xs, Iterable ys) { return filter(x -> find(eq(x), ys).fmap(constantly(true)).orElse(false), distinct(xs)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java index 27c5cf02e..4ff11cdec 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java @@ -21,7 +21,7 @@ private Intersperse() { } @Override - public Iterable apply(A a, Iterable as) { + public Iterable checkedApply(A a, Iterable as) { return tail(prependAll(a, as)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java index 75e7b4c24..cd5b061de 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java @@ -16,13 +16,13 @@ */ public final class Into implements Fn2, Map.Entry, C> { - private static final Into INSTANCE = new Into<>(); + private static final Into INSTANCE = new Into<>(); private Into() { } @Override - public C apply(BiFunction fn, Map.Entry entry) { + public C checkedApply(BiFunction fn, Map.Entry entry) { return fn.apply(entry.getKey(), entry.getValue()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java index a230d94b2..526fcb7e5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java @@ -15,10 +15,10 @@ */ public final class Into1 implements Fn2, SingletonHList, B> { - private static final Into1 INSTANCE = new Into1<>(); + private static final Into1 INSTANCE = new Into1<>(); @Override - public B apply(Function fn, SingletonHList singletonHList) { + public B checkedApply(Function fn, SingletonHList singletonHList) { return fn.apply(singletonHList.head()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java index f9ed9a6cc..05daec1ef 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java @@ -16,10 +16,10 @@ */ public final class Into3 implements Fn2, Product3, D> { - private static final Into3 INSTANCE = new Into3<>(); + private static final Into3 INSTANCE = new Into3<>(); @Override - public D apply(Fn3 fn, Product3 product) { + public D checkedApply(Fn3 fn, Product3 product) { return product.into(fn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java index 3544516eb..14dba6f90 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into4.java @@ -17,10 +17,11 @@ */ public final class Into4 implements Fn2, Product4, E> { - private static final Into4 INSTANCE = new Into4<>(); + private static final Into4 INSTANCE = new Into4<>(); @Override - public E apply(Fn4 fn, Product4 product) { + public E checkedApply(Fn4 fn, + Product4 product) { return product.into(fn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java index e59852f62..8cbdf25f5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into5.java @@ -18,11 +18,11 @@ */ public final class Into5 implements Fn2, Product5, F> { - private static final Into5 INSTANCE = new Into5<>(); + private static final Into5 INSTANCE = new Into5<>(); @Override - public F apply(Fn5 fn, - Product5 product) { + public F checkedApply(Fn5 fn, + Product5 product) { return product.into(fn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java index 1b4180688..0c59771f2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into6.java @@ -20,11 +20,11 @@ */ public final class Into6 implements Fn2, Product6, G> { - private static final Into6 INSTANCE = new Into6<>(); + private static final Into6 INSTANCE = new Into6<>(); @Override - public G apply(Fn6 fn, - Product6 product) { + public G checkedApply(Fn6 fn, + Product6 product) { return product.into(fn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java index fe4b0d7e4..612068814 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into7.java @@ -21,11 +21,12 @@ */ public final class Into7 implements Fn2, Product7, H> { - private static final Into7 INSTANCE = new Into7<>(); + private static final Into7 INSTANCE = new Into7<>(); @Override - public H apply(Fn7 fn, - Product7 product) { + public H checkedApply( + Fn7 fn, + Product7 product) { return product.into(fn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java index d41c7ff75..fdad33a72 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into8.java @@ -25,7 +25,7 @@ public final class Into8 implements Fn2 INSTANCE = new Into8<>(); @Override - public I apply( + public I checkedApply( Fn8 fn, Product8 product) { return product.into(fn); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java index 596bea845..17a96235c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java @@ -24,7 +24,7 @@ private Iterate() { } @Override - public Iterable apply(Function fn, A seed) { + public Iterable checkedApply(Function fn, A seed) { return unfoldr(a -> just(tuple(a, fn.apply(a))), seed); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java index b5ccf4e23..359d59b66 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LT.java @@ -23,7 +23,7 @@ private LT() { } @Override - public Boolean apply(A y, A x) { + public Boolean checkedApply(A y, A x) { return ltBy(id(), y, x); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java index 4287229c2..85f07b61e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LTE.java @@ -23,7 +23,7 @@ private LTE() { } @Override - public Boolean apply(A y, A x) { + public Boolean checkedApply(A y, A x) { return lteBy(id(), y, x); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java index 7b154b0ae..fe14186b7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java @@ -38,7 +38,7 @@ private LazyRec() { } @Override - public Lazy apply(BiFunction>, A, Lazy> fn, A a) { + public Lazy checkedApply(BiFunction>, A, Lazy> fn, A a) { return join(lazy(() -> fn.apply(nextA -> apply(fn, nextA), a))); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java index 686c521b0..6456f62fb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java @@ -33,7 +33,8 @@ private MagnetizeBy() { } @Override - public Iterable> apply(BiFunction predicate, Iterable as) { + public Iterable> checkedApply(BiFunction predicate, + Iterable as) { return () -> uncons(as).fmap(into((A head, Iterable tail) -> { Iterable group = cons(head, unfoldr(into((pivot, ys) -> uncons(ys) .flatMap(into((y, recurse) -> predicate.apply(pivot, y) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java index bc0085cf7..35c771ea1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java @@ -21,7 +21,7 @@ private Map() { } @Override - public Iterable apply(Function fn, Iterable as) { + public Iterable checkedApply(Function fn, Iterable as) { return new MappingIterable<>(fn, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java index 4a02e0ed5..8adb7e847 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java @@ -16,13 +16,13 @@ */ public final class Partial2 implements Fn2, A, Fn1> { - private static final Partial2 INSTANCE = new Partial2<>(); + private static final Partial2 INSTANCE = new Partial2<>(); private Partial2() { } @Override - public Fn1 apply(BiFunction fn, A a) { + public Fn1 checkedApply(BiFunction fn, A a) { return b -> fn.apply(a, b); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java index df9b804a5..151d8f20f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java @@ -16,13 +16,13 @@ */ public final class Partial3 implements Fn2, A, Fn2> { - private static final Partial3 INSTANCE = new Partial3<>(); + private static final Partial3 INSTANCE = new Partial3<>(); private Partial3() { } @Override - public Fn2 apply(Fn3 fn, A a) { + public Fn2 checkedApply(Fn3 fn, A a) { return fn.apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java index 368dfb0bb..41acd66b9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java @@ -26,14 +26,14 @@ */ public final class Partition implements Fn2>, Iterable, Tuple2, Iterable>> { - private static final Partition INSTANCE = new Partition<>(); + private static final Partition INSTANCE = new Partition<>(); private Partition() { } @Override - public Tuple2, Iterable> apply(Function> function, - Iterable as) { + public Tuple2, Iterable> checkedApply(Function> function, + Iterable as) { return Tuple2.>>fill(map(function, as)) .biMap(Map., Iterable>map(cp -> cp.match(Collections::singleton, __ -> emptySet())), Map., Iterable>map(cp -> cp.match(__ -> emptySet(), Collections::singleton))) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java index bd86c6856..c12c45d55 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java @@ -15,14 +15,14 @@ * @param the functor type */ public final class Peek> implements Fn2, FA, FA> { - private static final Peek INSTANCE = new Peek<>(); + private static final Peek INSTANCE = new Peek<>(); private Peek() { } @Override @SuppressWarnings("unchecked") - public FA apply(Consumer consumer, FA fa) { + public FA checkedApply(Consumer consumer, FA fa) { return (FA) fa.fmap(a -> { consumer.accept(a); return a; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java index e228293e5..f9d63e0b6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java @@ -26,7 +26,7 @@ private Peek2() { @Override @SuppressWarnings("unchecked") - public FAB apply(Consumer aConsumer, Consumer bConsumer, FAB fab) { + public FAB checkedApply(Consumer aConsumer, Consumer bConsumer, FAB fab) { return (FAB) fab.biMap(a -> { aConsumer.accept(a); return a; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java index 94ebd2c78..7b2ed2a64 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java @@ -19,7 +19,7 @@ private PrependAll() { } @Override - public Iterable apply(A a, Iterable as) { + public Iterable checkedApply(A a, Iterable as) { return () -> new PrependingIterator<>(a, as.iterator()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java index 150206f61..d77872e71 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java @@ -33,7 +33,7 @@ private ReduceLeft() { } @Override - public Maybe apply(BiFunction fn, Iterable as) { + public Maybe checkedApply(BiFunction fn, Iterable as) { Iterator iterator = as.iterator(); return !iterator.hasNext() ? nothing() : just(foldLeft(fn, iterator.next(), () -> iterator)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java index 14a39b20a..97ed627d5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java @@ -31,7 +31,7 @@ private ReduceRight() { } @Override - public final Maybe apply(BiFunction fn, Iterable as) { + public final Maybe checkedApply(BiFunction fn, Iterable as) { return reduceLeft((b, a) -> fn.apply(a, b), reverse(as)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java index c310ae8ec..98d436461 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Replicate.java @@ -19,7 +19,7 @@ private Replicate() { } @Override - public Iterable apply(Integer n, A a) { + public Iterable checkedApply(Integer n, A a) { return take(n, repeat(a)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java index fffe9b580..a00eaff48 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java @@ -42,7 +42,7 @@ private Sequence() { } @Override - public AppTrav apply(TravApp traversable, Function pure) { + public AppTrav checkedApply(TravApp traversable, Function pure) { return traversable.traverse(id(), pure); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java index caec56faa..1a65422d6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Slide.java @@ -27,7 +27,7 @@ private Slide() { } @Override - public Iterable> apply(Integer k, Iterable as) { + public Iterable> checkedApply(Integer k, Iterable as) { if (k == 0) throw new IllegalArgumentException("k must be greater than 0"); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java index dbf151ab5..67fe1a137 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java @@ -21,7 +21,7 @@ private Snoc() { } @Override - public Iterable apply(A a, Iterable as) { + public Iterable checkedApply(A a, Iterable as) { return new SnocIterable<>(a, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java index a5c52ed58..de3d55858 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java @@ -22,13 +22,13 @@ */ public final class SortBy> implements Fn2, Iterable, List> { - private static final SortBy INSTANCE = new SortBy<>(); + private static final SortBy INSTANCE = new SortBy<>(); private SortBy() { } @Override - public List apply(Function fn, Iterable as) { + public List checkedApply(Function fn, Iterable as) { return sortWith(comparing(fn), as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java index 4062d3ebe..2c93239ee 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortWith.java @@ -27,7 +27,7 @@ private SortWith() { } @Override - public List apply(Comparator comparator, Iterable as) { + public List checkedApply(Comparator comparator, Iterable as) { List result = toCollection(ArrayList::new, as); result.sort(comparator); return result; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java index 3450a9c49..d74702b35 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java @@ -23,7 +23,8 @@ private Span() { } @Override - public Tuple2, Iterable> apply(Function predicate, Iterable as) { + public Tuple2, Iterable> checkedApply(Function predicate, + Iterable as) { return Tuple2.fill(as).biMap(takeWhile(predicate), dropWhile(predicate)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java index 86c417a6d..dbc55e349 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java @@ -21,7 +21,7 @@ private Take() { } @Override - public Iterable apply(Integer n, Iterable as) { + public Iterable checkedApply(Integer n, Iterable as) { return new TakingIterable<>(n, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java index 29863e2bc..098cd6a17 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java @@ -23,7 +23,7 @@ private TakeWhile() { } @Override - public Iterable apply(Function predicate, Iterable as) { + public Iterable checkedApply(Function predicate, Iterable as) { return new PredicatedTakingIterable<>(predicate, as); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java index 4b41af1b8..cecaa1543 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToArray.java @@ -23,7 +23,7 @@ private ToArray() { @Override @SuppressWarnings("unchecked") - public A[] apply(Class arrayType, Iterable as) { + public A[] checkedApply(Class arrayType, Iterable as) { A[] array = (A[]) Array.newInstance(arrayType.getComponentType(), size(as).intValue()); if (as instanceof Collection) return ((Collection) as).toArray(array); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java index 545682fb6..3e2fb05e1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java @@ -22,7 +22,7 @@ private ToCollection() { } @Override - public C apply(Supplier cSupplier, Iterable as) { + public C checkedApply(Supplier cSupplier, Iterable as) { C c = cSupplier.get(); as.forEach(c::add); return c; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java index 2b21f5268..e674673fb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java @@ -25,7 +25,7 @@ private ToMap() { } @Override - public M apply(Supplier mSupplier, Iterable> entries) { + public M checkedApply(Supplier mSupplier, Iterable> entries) { return foldLeft((m, kv) -> { m.put(kv.getKey(), kv.getValue()); return m; diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java index 6b69f4441..939518d38 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Tupler2.java @@ -21,7 +21,7 @@ private Tupler2() { } @Override - public Tuple2 apply(A a, B b) { + public Tuple2 checkedApply(A a, B b) { return tuple(a, b); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java index efb79a76c..e0c63eeb2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java @@ -37,7 +37,7 @@ private Unfoldr() { } @Override - public Iterable apply(Function>> fn, B b) { + public Iterable checkedApply(Function>> fn, B b) { return () -> new UnfoldingIterator<>(fn, b); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java index 3e6ba39eb..8f896e14c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java @@ -23,7 +23,7 @@ private Zip() { } @Override - public Iterable> apply(Iterable as, Iterable bs) { + public Iterable> checkedApply(Iterable as, Iterable bs) { return zipWith(Tupler2.tupler().toBiFunction(), as, bs); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java index 451addf5c..ccb98929f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Between.java @@ -20,7 +20,7 @@ private Between() { } @Override - public Boolean apply(A lower, A upper, A a) { + public Boolean checkedApply(A lower, A upper, A a) { return clamp(lower, upper, a).equals(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java index 20de04a77..3343afae4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Clamp.java @@ -23,7 +23,7 @@ private Clamp() { } @Override - public A apply(A lower, A upper, A a) { + public A checkedApply(A lower, A upper, A a) { return max(min(lower, upper)).fmap(min(max(lower, upper))).apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java index 5ef1382f7..db202c66a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java @@ -26,7 +26,7 @@ private CmpEqBy() { } @Override - public Boolean apply(Function compareFn, A x, A y) { + public Boolean checkedApply(Function compareFn, A x, A y) { return compareFn.apply(x).compareTo(compareFn.apply(y)) == 0; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java index ec0ad331e..d7f9a24e6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java @@ -28,7 +28,7 @@ private FoldLeft() { } @Override - public B apply(BiFunction fn, B acc, Iterable as) { + public B checkedApply(BiFunction fn, B acc, Iterable as) { B accumulation = acc; for (A a : as) accumulation = fn.apply(accumulation, a); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java index 8741aadba..4086204ed 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java @@ -47,7 +47,8 @@ private FoldRight() { } @Override - public Lazy apply(BiFunction, ? extends Lazy> fn, Lazy acc, Iterable as) { + public Lazy checkedApply(BiFunction, ? extends Lazy> fn, Lazy acc, + Iterable as) { return lazyRec((f, lazyIt) -> lazyIt.flatMap(it -> it.hasNext() ? fn.apply(it.next(), f.apply(lazy(it))) : acc), diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java index 6dc2ddef1..0a6bf807d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java @@ -19,13 +19,13 @@ */ public final class GTBy> implements Fn3, A, A, Boolean> { - private static final GTBy INSTANCE = new GTBy<>(); + private static final GTBy INSTANCE = new GTBy<>(); private GTBy() { } @Override - public Boolean apply(Function compareFn, A y, A x) { + public Boolean checkedApply(Function compareFn, A y, A x) { return compareFn.apply(x).compareTo(compareFn.apply(y)) > 0; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java index 830eacb69..6c956e366 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java @@ -28,7 +28,7 @@ private GTEBy() { } @Override - public Boolean apply(Function compareFn, A y, A x) { + public Boolean checkedApply(Function compareFn, A y, A x) { return GTBy.gtBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java index b09fb69a2..be547f38b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java @@ -25,7 +25,7 @@ private LTBy() { } @Override - public Boolean apply(Function compareFn, A y, A x) { + public Boolean checkedApply(Function compareFn, A y, A x) { return compareFn.apply(x).compareTo(compareFn.apply(y)) < 0; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java index 2eb29c7e1..2dda81ce4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java @@ -28,7 +28,7 @@ private LTEBy() { } @Override - public Boolean apply(Function compareFn, A y, A x) { + public Boolean checkedApply(Function compareFn, A y, A x) { return LTBy.ltBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java index 55d58fb6a..fbfc78c06 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java @@ -32,7 +32,7 @@ private LiftA2() { } @Override - public AppC apply(BiFunction fn, AppA appA, AppB appB) { + public AppC checkedApply(BiFunction fn, AppA appA, AppB appB) { return appB.zip(appA.fmap(Fn2.fn2(fn))).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java index 400f1d267..f99e6ec8c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java @@ -26,7 +26,7 @@ private ScanLeft() { } @Override - public Iterable apply(BiFunction fn, B b, Iterable as) { + public Iterable checkedApply(BiFunction fn, B b, Iterable as) { return () -> new ScanningIterator<>(fn, b, as.iterator()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java index a12ab841f..10db14166 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java @@ -28,7 +28,7 @@ private Times() { } @Override - public A apply(Integer n, Function fn, A a) { + public A checkedApply(Integer n, Function fn, A a) { if (n < 0) throw new IllegalStateException("n must not be less than 0"); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java index 4341ca32f..218b1db48 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java @@ -25,7 +25,8 @@ private ZipWith() { } @Override - public Iterable apply(BiFunction zipper, Iterable as, Iterable bs) { + public Iterable checkedApply(BiFunction zipper, Iterable as, + Iterable bs) { return () -> new ZippingIterator<>(zipper, as.iterator(), bs.iterator()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java index 53d40315d..38f0bbe3e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java @@ -15,8 +15,8 @@ private IfThenElse() { } @Override - public B apply(Function predicate, Function thenCase, - Function elseCase, A a) { + public B checkedApply(Function predicate, Function thenCase, + Function elseCase, A a) { return predicate.apply(a) ? thenCase.apply(a) : elseCase.apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java index 43c9bc018..b8ccd2527 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java @@ -34,7 +34,7 @@ private LiftA3() { } @Override - public AppD apply(Fn3 fn, AppA appA, AppB appB, AppC appC) { + public AppD checkedApply(Fn3 fn, AppA appA, AppB appB, AppC appC) { return appC.zip(appB.zip(appA.fmap(fn))).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java index 970b61dfb..2da5fb3b2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java @@ -53,7 +53,7 @@ private RateLimit() { } @Override - public Iterable apply(Supplier instantSupplier, Long limit, Duration duration, Iterable as) { + public Iterable checkedApply(Supplier instantSupplier, Long limit, Duration duration, Iterable as) { if (limit < 1) throw new IllegalArgumentException("Limit must be greater than 0: " + limit); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java index 1187aa320..408f94652 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java @@ -38,7 +38,7 @@ private LiftA4() { } @Override - public AppE apply(Fn4 fn, AppA appA, AppB appB, AppC appC, AppD appD) { + public AppE checkedApply(Fn4 fn, AppA appA, AppB appB, AppC appC, AppD appD) { return appD.zip(appC.zip(appB.zip(appA.fmap(fn)))).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java index 24d83bca2..4711de30a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java @@ -42,7 +42,7 @@ private LiftA5() { } @Override - public AppF apply(Fn5 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE) { + public AppF checkedApply(Fn5 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE) { return appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn))))).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java index 804fb7b99..90234684d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java @@ -47,8 +47,8 @@ private LiftA6() { } @Override - public AppG apply(Fn6 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, - AppF appF) { + public AppG checkedApply(Fn6 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, + AppF appF) { return appF.zip(appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn)))))).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java index 359801ba7..90eab07a5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java @@ -50,8 +50,8 @@ private LiftA7() { } @Override - public AppH apply(Fn7 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, - AppF appF, AppG appG) { + public AppH checkedApply(Fn7 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, + AppF appF, AppG appG) { return appG.zip(appF.zip(appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn))))))).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java index 2d52b95d1..70e8f4fd7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java @@ -25,7 +25,7 @@ public final class Trampoline implements Fn2 INSTANCE = new Trampoline<>(); @Override - public B apply(Function> fn, A a) { + public B checkedApply(Function> fn, A a) { RecursiveResult next = fn.apply(a); while (next instanceof Recurse) next = fn.apply(((Recurse) next).a); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java index 352de9585..a28e90614 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java @@ -1,22 +1,37 @@ package com.jnape.palatable.lambda.functions.specialized; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.monoid.Monoid; @FunctionalInterface public interface BiMonoidFactory extends BiSemigroupFactory { @Override - default MonoidFactory apply(A a) { - return b -> apply(a, b); + Monoid checkedApply(A a, B b) throws Throwable; + + @Override + default MonoidFactory checkedApply(A a) throws Throwable { + return b -> checkedApply(a, b); + } + + @Override + default Monoid apply(A a, B b) { + try { + return checkedApply(a, b); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } } @Override - Monoid apply(A a, B b); + default MonoidFactory apply(A a) { + return b -> apply(a, b); + } @Override default BiMonoidFactory flip() { - return (b, a) -> apply(a, b); + return (b, a) -> checkedApply(a, b); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java index a2a16d899..5cf0a4a17 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiSemigroupFactory.java @@ -8,7 +8,17 @@ public interface BiSemigroupFactory extends Fn4 { @Override - Semigroup apply(A a, B b); + Semigroup checkedApply(A a, B b) throws Throwable; + + @Override + default C checkedApply(A a, B b, C c, C d) throws Throwable { + return checkedApply(a, b).checkedApply(c, d); + } + + @Override + default Semigroup apply(A a, B b) { + return Fn4.super.apply(a, b)::apply; + } @Override default SemigroupFactory apply(A a) { @@ -24,9 +34,4 @@ default BiSemigroupFactory flip() { default SemigroupFactory, C> uncurry() { return ab -> apply(ab._1(), ab._2()); } - - @Override - default C apply(A a, B b, C c, C d) { - return apply(a).apply(b).apply(c, d); - } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java index 68657a104..e4d993def 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java @@ -1,14 +1,24 @@ package com.jnape.palatable.lambda.functions.specialized; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.monoid.Monoid; public interface MonoidFactory extends SemigroupFactory { + @Override + Monoid checkedApply(A a) throws Throwable; + @Override default B apply(A a, B b, B c) { return apply(a).apply(b, c); } @Override - Monoid apply(A a); + default Monoid apply(A a) { + try { + return checkedApply(a); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java index 509499536..568e6ca2c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java @@ -14,7 +14,7 @@ private Noop() { } @Override - public void accept(A a) { + public void checkedAccept(A a) { } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java index 212488abe..0f63478f6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.functions.specialized; +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; @@ -8,7 +9,16 @@ * * @param the {@link Functor} to lift into */ +@FunctionalInterface public interface Pure> { - Functor apply(A a); + Functor checkedApply(A a) throws Throwable; + + default Functor apply(A a) { + try { + return checkedApply(a); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SemigroupFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SemigroupFactory.java index 4a47c277c..6d49d6a55 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SemigroupFactory.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SemigroupFactory.java @@ -7,10 +7,15 @@ public interface SemigroupFactory extends Fn3 { @Override - Semigroup apply(A a); + Semigroup checkedApply(A a) throws Throwable; @Override - default B apply(A a, B b, B c) { - return apply(a).apply(b, c); + default Semigroup apply(A a) { + return Fn3.super.apply(a)::apply; + } + + @Override + default B checkedApply(A a, B b, B c) throws Throwable { + return checkedApply(a).checkedApply(b, c); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java index 0dc24e4bb..65ee00c0e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java @@ -3,14 +3,14 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.io.IO; import java.util.function.Consumer; import java.util.function.Function; -import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; +import static com.jnape.palatable.lambda.io.IO.io; /** * Specialized {@link Effect} that can throw any {@link Throwable}. @@ -57,7 +57,7 @@ default IO checkedApply(A a) throws T { */ @Override default CheckedEffect diMapL(Function fn) { - return Effect.super.diMapL(fn)::accept; + return Effect.super.diMapL(fn)::checkedAccept; } /** @@ -65,7 +65,7 @@ default CheckedEffect diMapL(Function fn) { */ @Override default CheckedEffect contraMap(Function fn) { - return Effect.super.contraMap(fn)::accept; + return Effect.super.contraMap(fn)::checkedAccept; } /** @@ -73,7 +73,7 @@ default CheckedEffect contraMap(Function fn) { */ @Override default CheckedEffect compose(Function before) { - return Effect.super.compose(before)::accept; + return Effect.super.compose(before)::checkedAccept; } /** @@ -81,7 +81,7 @@ default CheckedEffect compose(Function before) */ @Override default CheckedEffect discardR(Applicative> appB) { - return Effect.super.discardR(appB)::accept; + return Effect.super.discardR(appB)::checkedAccept; } /** @@ -89,17 +89,9 @@ default CheckedEffect discardR(Applicative> appB) { */ @Override default CheckedEffect andThen(Consumer after) { - return Effect.super.andThen(after)::accept; + return Effect.super.andThen(after)::checkedAccept; } - /** - * A version of {@link Effect#accept} that can throw checked exceptions. - * - * @param a the effect argument - * @throws T any exception that can be thrown by this method - */ - void checkedAccept(A a) throws T; - /** * Convenience static factory method for constructing a {@link CheckedEffect} without an explicit cast or type * attribution at the call site. diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java index 4fd589c2a..1c8fb76b6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java @@ -40,13 +40,14 @@ default B apply(A a) { */ @Override default CheckedFn1 fmap(Function f) { - return Fn1.super.fmap(f)::apply; + return Fn1.super.fmap(f)::checkedApply; } /** * {@inheritDoc} */ @Override + @SuppressWarnings("overrides") default CheckedFn1 flatMap(Function>> f) { return Fn1.super.flatMap(f).>coerce()::apply; } @@ -56,7 +57,7 @@ default CheckedFn1 flatMap(Function CheckedFn1 discardL(Applicative> appB) { - return Fn1.super.discardL(appB)::apply; + return Fn1.super.discardL(appB)::checkedApply; } /** @@ -64,7 +65,7 @@ default CheckedFn1 discardL(Applicative> appB) { */ @Override default CheckedFn1 discardR(Applicative> appB) { - return Fn1.super.discardR(appB)::apply; + return Fn1.super.discardR(appB)::checkedApply; } /** @@ -72,7 +73,7 @@ default CheckedFn1 discardR(Applicative> appB) { */ @Override default CheckedFn1 zip(Applicative, Fn1> appFn) { - return Fn1.super.zip(appFn)::apply; + return Fn1.super.zip(appFn)::checkedApply; } /** @@ -105,7 +106,7 @@ default CheckedFn1 diMapR(Function fn) { @Override default CheckedFn1 diMap(Function lFn, Function rFn) { - return Fn1.super.diMap(lFn, rFn)::apply; + return Fn1.super.diMap(lFn, rFn)::checkedApply; } /** @@ -113,7 +114,7 @@ default CheckedFn1 diMap(Function lFn, */ @Override default CheckedFn1, Tuple2> cartesian() { - return Fn1.super.cartesian()::apply; + return Fn1.super.cartesian()::checkedApply; } /** @@ -121,7 +122,7 @@ default CheckedFn1, Tuple2> cartesian() { */ @Override default CheckedFn1> carry() { - return Fn1.super.carry()::apply; + return Fn1.super.carry()::checkedApply; } /** @@ -137,7 +138,7 @@ default CheckedFn1 contraMap(Function fn) { */ @Override default CheckedFn1 compose(Function before) { - return Fn1.super.compose(before)::apply; + return Fn1.super.compose(before)::checkedApply; } /** @@ -145,18 +146,9 @@ default CheckedFn1 compose(Function before) */ @Override default CheckedFn1 andThen(Function after) { - return Fn1.super.andThen(after)::apply; + return Fn1.super.andThen(after)::checkedApply; } - /** - * A version of {@link Fn1#apply} that can throw checked exceptions. - * - * @param a the function argument - * @return the application of the argument to the function - * @throws T any exception that can be thrown by this method - */ - B checkedApply(A a) throws T; - /** * Convenience static factory method for constructing a {@link CheckedFn1} without an explicit cast or type * attribution at the call site. diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java index 88d13a1d6..3ff2d3e0b 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java @@ -110,7 +110,7 @@ public A identity() { } @Override - public A apply(A x, A y) { + public A checkedApply(A x, A y) { return semigroup.apply(x, y); } }; @@ -124,7 +124,7 @@ public A identity() { } @Override - public A apply(A x, A y) { + public A checkedApply(A x, A y) { return semigroup.apply(x, y); } }; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java index 5b93eac91..383116e6d 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java @@ -21,13 +21,13 @@ */ public final class AddAll> implements MonoidFactory, C> { - private static final AddAll INSTANCE = new AddAll<>(); + private static final AddAll INSTANCE = new AddAll<>(); private AddAll() { } @Override - public Monoid apply(Supplier cSupplier) { + public Monoid checkedApply(Supplier cSupplier) { return new Monoid() { @Override public C identity() { @@ -35,7 +35,7 @@ public C identity() { } @Override - public C apply(C xs, C ys) { + public C checkedApply(C xs, C ys) { C c = identity(); c.addAll(xs); c.addAll(ys); diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java index 3465ca0f8..e47e67df4 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java @@ -29,7 +29,7 @@ public Boolean identity() { } @Override - public Boolean apply(Boolean x, Boolean y) { + public Boolean checkedApply(Boolean x, Boolean y) { return x && y; } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java index 336e3cf6e..7713431b5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Collapse.java @@ -29,9 +29,10 @@ private Collapse() { } @Override - public Monoid> apply(Monoid<_1> _1Monoid, Monoid<_2> _2Monoid) { - Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.Collapse.collapse(_1Monoid, _2Monoid); - return Monoid.>monoid(semigroup, () -> tuple(_1Monoid.identity(), _2Monoid.identity())); + public Monoid> checkedApply(Monoid<_1> _1Monoid, Monoid<_2> _2Monoid) { + return Monoid.>monoid( + com.jnape.palatable.lambda.semigroup.builtin.Collapse.collapse(_1Monoid, _2Monoid), + () -> tuple(_1Monoid.identity(), _2Monoid.identity())); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java index 6c9945784..f9c53ed27 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java @@ -30,7 +30,7 @@ private Compose() { } @Override - public Monoid> apply(Monoid aMonoid) { + public Monoid> checkedApply(Monoid aMonoid) { return monoid(com.jnape.palatable.lambda.semigroup.builtin.Compose.compose(aMonoid), (Supplier>) () -> completedFuture(aMonoid.identity())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java index dd1ae290e..c02c09586 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java @@ -28,7 +28,7 @@ public Iterable identity() { } @Override - public Iterable apply(Iterable xs, Iterable ys) { + public Iterable checkedApply(Iterable xs, Iterable ys) { return new ConcatenatingIterable<>(xs, ys); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java index a5f1fcc0d..75a4090ba 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java @@ -19,17 +19,17 @@ public final class Endo implements Monoid> { private Endo() { } + public A apply(Fn1 f, Fn1 g, A a) { + return apply(f, g).apply(a); + } + @Override public Fn1 identity() { return id(); } - public A apply(Fn1 f, Fn1 g, A a) { - return apply(f, g).apply(a); - } - @Override - public Fn1 apply(Fn1 f, Fn1 g) { + public Fn1 checkedApply(Fn1 f, Fn1 g) { return f.fmap(g); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java index 9d074aaea..69b1e356c 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java @@ -34,7 +34,7 @@ public Maybe identity() { } @Override - public Maybe apply(Maybe x, Maybe y) { + public Maybe checkedApply(Maybe x, Maybe y) { return x.fmap(Maybe::just).orElse(y); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Join.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Join.java index 9f3713283..571bcbe73 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Join.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Join.java @@ -21,7 +21,7 @@ public String identity() { } @Override - public String apply(String x, String y) { + public String checkedApply(String x, String y) { return x + y; } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java index 775e6448f..8b0c91073 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Last.java @@ -30,7 +30,7 @@ public Maybe identity() { } @Override - public Maybe apply(Maybe x, Maybe y) { + public Maybe checkedApply(Maybe x, Maybe y) { return first(y, x); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java index 906a34658..ca2f4634b 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAll.java @@ -35,7 +35,7 @@ private LeftAll() { } @Override - public Monoid> apply(Monoid lMonoid) { + public Monoid> checkedApply(Monoid lMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.LeftAll.leftAll(lMonoid); return Monoid.>monoid(semigroup, () -> left(lMonoid.identity())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java index 9ba5a8cc7..461738188 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/LeftAny.java @@ -29,13 +29,13 @@ */ public final class LeftAny implements MonoidFactory, Either> { - private static final LeftAny INSTANCE = new LeftAny<>(); + private static final LeftAny INSTANCE = new LeftAny<>(); private LeftAny() { } @Override - public Monoid> apply(Monoid lMonoid) { + public Monoid> checkedApply(Monoid lMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.LeftAny.leftAny(lMonoid); return Monoid.>monoid(semigroup, () -> left(lMonoid.identity())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java index 5b6f7f8df..83b3afa41 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Merge.java @@ -22,13 +22,13 @@ */ public final class Merge implements BiMonoidFactory, Monoid, Either> { - private static final Merge INSTANCE = new Merge<>(); + private static final Merge INSTANCE = new Merge<>(); private Merge() { } @Override - public Monoid> apply(Semigroup lSemigroup, Monoid rMonoid) { + public Monoid> checkedApply(Semigroup lSemigroup, Monoid rMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.Merge.merge(lSemigroup, rMonoid); return Monoid.>monoid(semigroup, () -> right(rMonoid.identity())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java index 4e5b54ea2..9f594df75 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java @@ -27,7 +27,7 @@ private MergeMaps() { } @Override - public Monoid> apply(Supplier> mSupplier, Semigroup semigroup) { + public Monoid> checkedApply(Supplier> mSupplier, Semigroup semigroup) { return Monoid.>monoid((x, y) -> { Map copy = mSupplier.get(); copy.putAll(x); diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java index a8157d0fb..90e57807d 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java @@ -28,7 +28,7 @@ public Boolean identity() { } @Override - public Boolean apply(Boolean x, Boolean y) { + public Boolean checkedApply(Boolean x, Boolean y) { return x || y; } @@ -39,7 +39,7 @@ public boolean test(Boolean x, Boolean y) { @Override public Boolean foldMap(Function fn, Iterable bs) { - return find(fn::apply, bs).fmap(constantly(true)).orElse(false); + return find(fn, bs).fmap(constantly(true)).orElse(false); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java index 2fc0731d5..71dc4e95f 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java @@ -35,7 +35,7 @@ private Present() { } @Override - public Monoid> apply(Semigroup aSemigroup) { + public Monoid> checkedApply(Semigroup aSemigroup) { return monoid((maybeX, maybeY) -> first(maybeX.fmap(x -> maybeY.fmap(aSemigroup.apply(x)).orElse(x)), maybeY), nothing()); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/PutAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/PutAll.java index b5c4e7ef8..b3462f175 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/PutAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/PutAll.java @@ -25,7 +25,7 @@ public HMap identity() { } @Override - public HMap apply(HMap x, HMap y) { + public HMap checkedApply(HMap x, HMap y) { return x.putAll(y); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAll.java index f68fb82e2..6968ea72c 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAll.java @@ -33,7 +33,7 @@ private RightAll() { } @Override - public Monoid> apply(Monoid rMonoid) { + public Monoid> checkedApply(Monoid rMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.RightAll.rightAll(rMonoid); return Monoid.>monoid(semigroup, () -> right(rMonoid.identity())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java index ff25246c7..277ec5163 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RightAny.java @@ -29,13 +29,13 @@ */ public final class RightAny implements MonoidFactory, Either> { - private static final RightAny INSTANCE = new RightAny<>(); + private static final RightAny INSTANCE = new RightAny<>(); private RightAny() { } @Override - public Monoid> apply(Monoid rMonoid) { + public Monoid> checkedApply(Monoid rMonoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.RightAny.rightAny(rMonoid); return Monoid.>monoid(semigroup, () -> right(rMonoid.identity())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java index b3ab1c93e..7533f9c41 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/RunAll.java @@ -1,8 +1,8 @@ package com.jnape.palatable.lambda.monoid.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.Monoid; import com.jnape.palatable.lambda.semigroup.Semigroup; @@ -23,7 +23,7 @@ private RunAll() { } @Override - public Monoid> apply(Monoid monoid) { + public Monoid> checkedApply(Monoid monoid) { Semigroup> semigroup = com.jnape.palatable.lambda.semigroup.builtin.RunAll.runAll(monoid); return monoid(semigroup, io(monoid.identity())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java index 4594f328e..8da150dc5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java @@ -26,7 +26,7 @@ public Iterable identity() { } @Override - public Iterable apply(Iterable xs, Iterable ys) { + public Iterable checkedApply(Iterable xs, Iterable ys) { return new UnioningIterable<>(xs, ys); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java index 860df1e6f..4e17c6e97 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java @@ -26,7 +26,7 @@ public Boolean identity() { } @Override - public Boolean apply(Boolean x, Boolean y) { + public Boolean checkedApply(Boolean x, Boolean y) { return x ^ y; } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java index 425f47dcf..04b03442f 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Matching.java @@ -16,7 +16,7 @@ private Matching() { } @Override - public Either apply(Optic, ? super Identity, S, T, A, B> optic, S s) { + public Either checkedApply(Optic, ? super Identity, S, T, A, B> optic, S s) { Market> market = new Market<>(Identity::new, Either::right); return optic., Identity, diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java index cf73de8ad..d15c8bfae 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java @@ -32,9 +32,9 @@ private Over() { } @Override - public T apply(Optic, ? super Identity, S, T, A, B> optic, - Function fn, - S s) { + public T checkedApply(Optic, ? super Identity, S, T, A, B> optic, + Function fn, + S s) { return optic., Identity, Identity, Identity, Fn1>, Fn1>>apply( a -> new Identity<>(fn.apply(a))).apply(s).runIdentity(); } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java index edbd9e9c0..977788eac 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java @@ -28,7 +28,7 @@ private Pre() { } @Override - public Optic, Const, ?>, S, T, Maybe, B> apply( + public Optic, Const, ?>, S, T, Maybe, B> checkedApply( Optic, ? super Const, ?>, S, T, A, B> optic) { Optic, ? super Const, ?>, S, T, Maybe, B> mappedOptic = optic.mapA(Maybe::just); return reframe(mappedOptic); @@ -51,7 +51,7 @@ public static Pre pre() { Optic, Const, ?>, S, T, A, B> optic = protoOptic .toOptic(new Pure, ?>>() { @Override - public Const, X> apply(X x) { + public Const, X> checkedApply(X x) { return new Const<>(nothing()); } }); diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java index a61841058..eeb36f5b8 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java @@ -26,7 +26,7 @@ private Re() { } @Override - public Optic, Const, B, B, T, T> apply( + public Optic, Const, B, B, T, T> checkedApply( Optic, ? super Identity, S, T, A, B> optic) { return Optic., Const, B, B, T, T, Const, Const, diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java index 1921c45c6..7fdd16e56 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Set.java @@ -31,7 +31,7 @@ private Set() { } @Override - public T apply(Optic, ? super Identity, S, T, A, B> optic, B b, S s) { + public T checkedApply(Optic, ? super Identity, S, T, A, B> optic, B b, S s) { return over(optic, constantly(b), s); } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java index 7356d3ec1..ce63ea01a 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java @@ -30,9 +30,9 @@ private Under() { } @Override - public A apply(Optic, ? super Identity, S, T, A, B> optic, - Function fn, - B b) { + public A checkedApply(Optic, ? super Identity, S, T, A, B> optic, + Function fn, + B b) { Exchange> exchange = optic.apply(new Exchange<>(id(), Identity::new)); return exchange.sa().apply(fn.apply(exchange.bt().apply(b).runIdentity())); } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java index 1a80c025e..c63074ac2 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/View.java @@ -27,7 +27,7 @@ private View() { } @Override - public A apply(Optic, ? super Const, S, T, A, B> optic, S s) { + public A checkedApply(Optic, ? super Const, S, T, A, B> optic, S s) { return optic., Const, Const, Const, Fn1>, Fn1>>apply( Const::new).apply(s).runConst(); } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java index 1e8c6ef1c..97ccfa54a 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java @@ -31,7 +31,7 @@ private Absent() { } @Override - public Semigroup> apply(Semigroup aSemigroup) { + public Semigroup> checkedApply(Semigroup aSemigroup) { return LiftA2., Maybe, Maybe, Maybe>liftA2(aSemigroup.toBiFunction())::apply; } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java index d1a3b6eca..7b163898d 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Collapse.java @@ -21,13 +21,13 @@ */ public final class Collapse<_1, _2> implements BiSemigroupFactory, Semigroup<_2>, Tuple2<_1, _2>> { - private static final Collapse INSTANCE = new Collapse<>(); + private static final Collapse INSTANCE = new Collapse<>(); private Collapse() { } @Override - public Semigroup> apply(Semigroup<_1> _1Semigroup, Semigroup<_2> _2Semigroup) { + public Semigroup> checkedApply(Semigroup<_1> _1Semigroup, Semigroup<_2> _2Semigroup) { return (x, y) -> x.biMap(_1Semigroup.flip().apply(y._1()), _2Semigroup.flip().apply(y._2())); } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java index 0bb9a2a41..cba9a218f 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Compose.java @@ -26,7 +26,7 @@ private Compose() { } @Override - public Semigroup> apply(Semigroup aSemigroup) { + public Semigroup> checkedApply(Semigroup aSemigroup) { return (futureX, futureY) -> futureX.thenCompose(x -> futureY.thenApply(y -> aSemigroup.apply(x, y))); } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java index 780c61f89..e5ac2caf1 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAll.java @@ -30,13 +30,13 @@ */ public final class LeftAll implements SemigroupFactory, Either> { - private static final LeftAll INSTANCE = new LeftAll<>(); + private static final LeftAll INSTANCE = new LeftAll<>(); private LeftAll() { } @Override - public Semigroup> apply(Semigroup lSemigroup) { + public Semigroup> checkedApply(Semigroup lSemigroup) { return (x, y) -> x.match(xL -> y.match(yL -> left(lSemigroup.apply(xL, yL)), Either::right), Either::right); } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java index 233246b89..91a892dfb 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAny.java @@ -35,7 +35,7 @@ private LeftAny() { } @Override - public Semigroup> apply(Semigroup lSemigroup) { + public Semigroup> checkedApply(Semigroup lSemigroup) { return (x, y) -> x.match(xL -> y.match(yL -> left(lSemigroup.apply(xL, yL)), yR -> left(xL)), xR -> y); diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java index 001a39a3e..a9cc3db66 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Max.java @@ -26,7 +26,7 @@ private Max() { } @Override - public A apply(A x, A y) { + public A checkedApply(A x, A y) { return maxBy(id(), x, y); } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java index d00bcbb4b..bc97f7d9c 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java @@ -24,13 +24,13 @@ */ public final class MaxBy> implements SemigroupFactory, A> { - private static final MaxBy INSTANCE = new MaxBy<>(); + private static final MaxBy INSTANCE = new MaxBy<>(); private MaxBy() { } @Override - public Semigroup apply(Function compareFn) { + public Semigroup checkedApply(Function compareFn) { return (x, y) -> ltBy(compareFn, y, x) ? y : x; } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java index eaf5e355b..833e1aa57 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Merge.java @@ -26,7 +26,7 @@ private Merge() { } @Override - public Semigroup> apply(Semigroup lSemigroup, Semigroup rSemigroup) { + public Semigroup> checkedApply(Semigroup lSemigroup, Semigroup rSemigroup) { return (x, y) -> x.merge(lSemigroup::apply, rSemigroup::apply, y); } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java index f700e4612..747bd5d25 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Min.java @@ -26,7 +26,7 @@ private Min() { } @Override - public A apply(A x, A y) { + public A checkedApply(A x, A y) { return minBy(id(), x, y); } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java index 4458a55bc..c425c5121 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java @@ -24,13 +24,13 @@ */ public final class MinBy> implements SemigroupFactory, A> { - private static final MinBy INSTANCE = new MinBy<>(); + private static final MinBy INSTANCE = new MinBy<>(); private MinBy() { } @Override - public Semigroup apply(Function compareFn) { + public Semigroup checkedApply(Function compareFn) { return (x, y) -> gtBy(compareFn, y, x) ? y : x; } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java index 8c69fbd94..5bb6fa018 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAll.java @@ -29,13 +29,13 @@ */ public final class RightAll implements SemigroupFactory, Either> { - private static final RightAll INSTANCE = new RightAll<>(); + private static final RightAll INSTANCE = new RightAll<>(); private RightAll() { } @Override - public Semigroup> apply(Semigroup rSemigroup) { + public Semigroup> checkedApply(Semigroup rSemigroup) { return (eitherX, eitherY) -> eitherX.flatMap(xR -> eitherY.flatMap(yR -> right(rSemigroup.apply(xR, yR)))); } diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java index 7d2f1d864..264fad155 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java @@ -30,13 +30,13 @@ */ public final class RightAny implements SemigroupFactory, Either> { - private static final RightAny INSTANCE = new RightAny<>(); + private static final RightAny INSTANCE = new RightAny<>(); private RightAny() { } @Override - public Semigroup> apply(Semigroup rSemigroup) { + public Semigroup> checkedApply(Semigroup rSemigroup) { return (x, y) -> x.match(constantly(y), xR -> y.match(constantly(right(xR)), rSemigroup.apply(xR).andThen(Either::right))); diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java index 34a2eeb2b..f84d0243a 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RunAll.java @@ -1,8 +1,8 @@ package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.semigroup.Semigroup; /** @@ -19,7 +19,7 @@ private RunAll() { } @Override - public Semigroup> apply(Semigroup semigroup) { + public Semigroup> checkedApply(Semigroup semigroup) { return (ioX, ioY) -> ioY.zip(ioX.fmap(semigroup)); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java index 9f5dabd60..ca3505a0e 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java @@ -19,12 +19,12 @@ public class EffectTest { public void covariantReturns() { List results = new ArrayList<>(); - Effect effect = results::add; - Effect diMapL = effect.diMapL(Object::toString); - Effect contraMap = effect.contraMap(Object::toString); - Effect compose = effect.compose(Object::toString); + Effect effect = results::add; + Effect diMapL = effect.diMapL(Object::toString); + Effect contraMap = effect.contraMap(Object::toString); + Effect compose = effect.compose(Object::toString); Effect stringEffect = effect.discardR(constantly("1")); - Effect andThen = effect.andThen(effect); + Effect andThen = effect.andThen(effect); effect.accept("1"); diMapL.accept("2"); diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java index c506f357c..b169b7870 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java @@ -56,7 +56,7 @@ public void recursiveStackSafety() { assertEquals(STACK_EXPLODING_NUMBER, new Fn1, Lazy>() { @Override - public Lazy apply(Lazy lazyX) { + public Lazy checkedApply(Lazy lazyX) { return lazyX.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(lazy(x + 1)) : lazy(x)); diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 0c9ba0535..674bb8e8d 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -142,7 +142,7 @@ public void recursiveSyncFlatMapStackSafety() { assertEquals(STACK_EXPLODING_NUMBER, new Fn1, IO>() { @Override - public IO apply(IO a) { + public IO checkedApply(IO a) { return a.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(io(x + 1)) : io(x)); } }.apply(io(0)).unsafePerformIO()); @@ -172,7 +172,7 @@ public void recursiveAsyncFlatMapStackSafety() { assertEquals(STACK_EXPLODING_NUMBER, new Fn1, IO>() { @Override - public IO apply(IO a) { + public IO checkedApply(IO a) { return a.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(io(x + 1)) : io(x)); } }.apply(io(0)).unsafePerformAsyncIO().join()); From 74f70bd962dda001f423976f1b86e302881c735c Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 6 May 2019 20:06:30 -0500 Subject: [PATCH 144/348] Eliminating all checked variants of Fn1 and friends --- CHANGELOG.md | 8 +- .../jnape/palatable/lambda/adt/Either.java | 13 +- .../com/jnape/palatable/lambda/adt/Maybe.java | 9 +- .../com/jnape/palatable/lambda/adt/Try.java | 77 ++++---- .../specialized/checked/CheckedEffect.java | 107 ------------ .../specialized/checked/CheckedFn1.java | 165 ------------------ .../specialized/checked/CheckedRunnable.java | 17 -- .../specialized/checked/CheckedSupplier.java | 145 --------------- .../com/jnape/palatable/lambda/io/IO.java | 17 +- .../checked/CheckedEffectTest.java | 34 ---- .../specialized/checked/CheckedFn1Test.java | 47 ----- .../checked/CheckedSupplierTest.java | 42 ----- .../com/jnape/palatable/lambda/io/IOTest.java | 19 +- 13 files changed, 71 insertions(+), 629 deletions(-) delete mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java delete mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java delete mode 100644 src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java delete mode 100644 src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java delete mode 100644 src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index eb5b0499e..bad86b559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Changed - ***Breaking Change***: `IO` is now sealed and moved to its own package. Most previous constructions using the static -factory methods should continue to work (by simply targeting `Supplier` now instead of an anonymous `IO`), but some -might need to be reworked, and subtyping is obviously no longer supported. + factory methods should continue to work (by simply targeting `Supplier` now instead of an + anonymous `IO`), but some might need to be reworked, and subtyping is obviously no longer + supported. - ***Breaking Change***: `FoldRight` now requires `Lazy` as part of its interface to support short-circuiting operations - ***Breaking Change***: Eliminated all raw types and java11 warnings. This required using capture in unification parameters for Functor and friends, so nearly every functor's type-signature changed. @@ -19,7 +20,8 @@ might need to be reworked, and subtyping is obviously no longer supported. exceptions that could be caught by corresponding catch blocks - ***Breaking Change***: All `Fn*` types target methods now support throwing `Throwable`; `apply` is now defaulted and will simply bypass javac to throw checked exceptions as if they were unchecked. This allows all - checked variants to be eliminated + checked variants to be eliminated +- ***Breaking Change***: All `Checked` variants have been eliminated - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ### Added 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 e248eef92..e6c0aeebb 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -3,10 +3,11 @@ import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek2; import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -318,7 +319,7 @@ public static Either fromMaybe(Maybe maybe, Supplier leftFn) } /** - * Attempt to execute the {@link CheckedSupplier}, returning its result in a right value. If the supplier throws an + * Attempt to execute the {@link Fn0}, 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 @@ -327,20 +328,20 @@ public static Either fromMaybe(Maybe maybe, Supplier leftFn) * @param the right parameter type * @return the supplier result as a right value, or leftFn's mapping result as a left value */ - public static Either trying(CheckedSupplier supplier, + public static Either trying(Fn0 supplier, Function leftFn) { - return Try.trying(supplier::get).toEither(leftFn); + return Try.trying(supplier::get).toEither(leftFn); } /** - * Attempt to execute the {@link CheckedSupplier}, returning its result in a right value. If the supplier throws an + * Attempt to execute the {@link Fn0}, returning its result in a right value. If the supplier throws an * exception, wrap it in a left value and return it. * * @param supplier the supplier of the right value * @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) { + public static Either trying(Fn0 supplier) { return trying(supplier, id()); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index 67c1fd886..892edc8ab 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -5,8 +5,8 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -21,6 +21,7 @@ import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -69,10 +70,10 @@ public final A orElse(A other) { * @return the value, if present * @throws E the throwable, if the value is absent */ - public final A orElseThrow(Supplier throwableSupplier) throws E { - return orElseGet((CheckedSupplier) () -> { + public final A orElseThrow(Fn0 throwableSupplier) throws E { + return orElseGet(fn0(() -> { throw throwableSupplier.get(); - }); + })); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index fe1581307..bec29194a 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -1,9 +1,9 @@ package com.jnape.palatable.lambda.adt; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier; import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -237,11 +237,10 @@ public static Try failure(T t) { * Execute supplier, returning a success A or a failure of the thrown {@link Throwable}. * * @param supplier the supplier - * @param the possible {@link Throwable} type * @param the possible success type * @return a new {@link Try} around either a successful A result or the thrown {@link Throwable} */ - public static Try trying(CheckedSupplier supplier) { + public static Try trying(Fn0 supplier) { try { return success(supplier.get()); } catch (Throwable t) { @@ -263,7 +262,7 @@ public static Try trying(CheckedRunnable runnable) { } /** - * Given a {@link CheckedSupplier}<{@link AutoCloseable}> aSupplier and a + * Given a {@link Fn0}<{@link AutoCloseable}> aSupplier and a * {@link Function} fn, apply fn to the result of aSupplier, ensuring * that the result has its {@link AutoCloseable#close() close} method invoked, regardless of the outcome. *

@@ -283,65 +282,63 @@ public static Try trying(CheckedRunnable runnable) { * * try-with-resources, introduced in Java 7. * - * @param aSupplier the resource supplier - * @param fn the function body - * @param the resource type - * @param the function return type + * @param fn0 the resource supplier + * @param fn the function body + * @param the resource type + * @param the function return type * @return a {@link Try} representing the result of the function's application to the resource */ @SuppressWarnings("try") public static Try withResources( - CheckedSupplier aSupplier, - CheckedFn1> fn) { + Fn0 fn0, + Fn1> fn) { return trying(() -> { - try (A resource = aSupplier.get()) { + try (A resource = fn0.apply()) { return fn.apply(resource).fmap(upcast()); } }).flatMap(id()); } /** - * Convenience overload of {@link Try#withResources(CheckedSupplier, CheckedFn1) withResources} that cascades - * dependent resource creation via nested calls. + * Convenience overload of {@link Try#withResources(Fn0, Fn1) withResources} that cascades dependent resource + * creation via nested calls. * - * @param aSupplier the first resource supplier - * @param bFn the dependent resource function - * @param fn the function body - * @param the first resource type - * @param the second resource type - * @param the function return type + * @param fn0 the first resource supplier + * @param bFn the dependent resource function + * @param fn the function body + * @param the first resource type + * @param the second resource type + * @param the function return type * @return a {@link Try} representing the result of the function's application to the dependent resource */ public static Try withResources( - CheckedSupplier aSupplier, - CheckedFn1 bFn, - CheckedFn1> fn) { - CheckedFn1> checkedFn = a -> withResources(() -> bFn.apply(a), fn::apply); - return withResources(aSupplier, checkedFn); + Fn0 fn0, + Fn1 bFn, + Fn1> fn) { + return withResources(fn0, a -> withResources(() -> bFn.apply(a), fn::apply)); } /** - * Convenience overload of {@link Try#withResources(CheckedSupplier, CheckedFn1, CheckedFn1) withResources} that + * Convenience overload of {@link Try#withResources(Fn0, Fn1, Fn1) withResources} that * cascades * two dependent resource creations via nested calls. * - * @param aSupplier the first resource supplier - * @param bFn the second resource function - * @param cFn the final resource function - * @param fn the function body - * @param the first resource type - * @param the second resource type - * @param the final resource type - * @param the function return type + * @param fn0 the first resource supplier + * @param bFn the second resource function + * @param cFn the final resource function + * @param fn the function body + * @param the first resource type + * @param the second resource type + * @param the final resource type + * @param the function return type * @return a {@link Try} representing the result of the function's application to the final dependent resource */ public static Try withResources( - CheckedSupplier aSupplier, - CheckedFn1 bFn, - CheckedFn1 cFn, - CheckedFn1> fn) { - CheckedFn1> checkedFn = b -> withResources(() -> cFn.apply(b), fn::apply); - return withResources(aSupplier, bFn, checkedFn); + Fn0 fn0, + Fn1 bFn, + Fn1 cFn, + Fn1> fn) { + return withResources(fn0, bFn, b -> withResources(() -> cFn.apply(b), fn::apply)); } private static final class Failure extends Try { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java index 65ee00c0e..e69de29bb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java @@ -1,107 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.functions.Effect; -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.io.IO; - -import java.util.function.Consumer; -import java.util.function.Function; - -import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; -import static com.jnape.palatable.lambda.io.IO.io; - -/** - * Specialized {@link Effect} that can throw any {@link Throwable}. - * - * @param The {@link Throwable} type - * @param The input type - * @see CheckedRunnable - * @see CheckedFn1 - * @see Effect - */ -@FunctionalInterface -public interface CheckedEffect extends Effect, CheckedFn1> { - - /** - * {@inheritDoc} - */ - @Override - default void accept(A a) { - try { - checkedAccept(a); - } catch (Throwable t) { - throw throwChecked(t); - } - } - - /** - * {@inheritDoc} - */ - @Override - default IO apply(A a) { - return io(() -> accept(a)); - } - - /** - * {@inheritDoc} - */ - @Override - default IO checkedApply(A a) throws T { - return apply(a); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect diMapL(Function fn) { - return Effect.super.diMapL(fn)::checkedAccept; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect contraMap(Function fn) { - return Effect.super.contraMap(fn)::checkedAccept; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect compose(Function before) { - return Effect.super.compose(before)::checkedAccept; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect discardR(Applicative> appB) { - return Effect.super.discardR(appB)::checkedAccept; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedEffect andThen(Consumer after) { - return Effect.super.andThen(after)::checkedAccept; - } - - /** - * Convenience static factory method for constructing a {@link CheckedEffect} without an explicit cast or type - * attribution at the call site. - * - * @param checkedEffect the checked effect - * @param the inferred Throwable type - * @param the input type - * @return the checked effect - */ - static CheckedEffect checked(CheckedEffect checkedEffect) { - return checkedEffect; - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java deleted file mode 100644 index 1c8fb76b6..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; - -import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; - -/** - * Specialized {@link Fn1} that can throw any {@link Throwable}. - * - * @param The {@link Throwable} type - * @param The input type - * @param The output type - * @see CheckedSupplier - * @see CheckedRunnable - * @see Fn1 - */ -@FunctionalInterface -public interface CheckedFn1 extends Fn1 { - - /** - * {@inheritDoc} - */ - @Override - default B apply(A a) { - try { - return checkedApply(a); - } catch (Throwable t) { - throw throwChecked(t); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 fmap(Function f) { - return Fn1.super.fmap(f)::checkedApply; - } - - /** - * {@inheritDoc} - */ - @Override - @SuppressWarnings("overrides") - default CheckedFn1 flatMap(Function>> f) { - return Fn1.super.flatMap(f).>coerce()::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 discardL(Applicative> appB) { - return Fn1.super.discardL(appB)::checkedApply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 discardR(Applicative> appB) { - return Fn1.super.discardR(appB)::checkedApply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 zip(Applicative, Fn1> appFn) { - return Fn1.super.zip(appFn)::checkedApply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 zip(Fn2 appFn) { - return Fn1.super.zip(appFn).coerce(); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 diMapL(Function fn) { - return Fn1.super.diMapL(fn).coerce(); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 diMapR(Function fn) { - return Fn1.super.diMapR(fn).coerce(); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 diMap(Function lFn, - Function rFn) { - return Fn1.super.diMap(lFn, rFn)::checkedApply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1, Tuple2> cartesian() { - return Fn1.super.cartesian()::checkedApply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1> carry() { - return Fn1.super.carry()::checkedApply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 contraMap(Function fn) { - return Fn1.super.contraMap(fn).coerce(); - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 compose(Function before) { - return Fn1.super.compose(before)::checkedApply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedFn1 andThen(Function after) { - return Fn1.super.andThen(after)::checkedApply; - } - - /** - * Convenience static factory method for constructing a {@link CheckedFn1} without an explicit cast or type - * attribution at the call site. - * - * @param checkedFn1 the checked fn1 - * @param the inferred Throwable type - * @param the input type - * @param the output type - * @return the checked fn1 - */ - static CheckedFn1 checked(CheckedFn1 checkedFn1) { - return checkedFn1; - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java index 954f4b952..c3f1bbd51 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java @@ -1,16 +1,11 @@ package com.jnape.palatable.lambda.functions.specialized.checked; -import com.jnape.palatable.lambda.adt.Unit; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; /** * Specialized {@link Runnable} that can throw any {@link Throwable}. * * @param The {@link Throwable} type - * @see CheckedSupplier - * @see CheckedFn1 */ @FunctionalInterface public interface CheckedRunnable extends Runnable { @@ -31,18 +26,6 @@ default void run() { } } - /** - * Convert this {@link CheckedRunnable} to a {@link CheckedSupplier} that returns {@link Unit}. - * - * @return the checked supplier - */ - default CheckedSupplier toSupplier() { - return () -> { - run(); - return UNIT; - }; - } - /** * Convenience static factory method for constructing a {@link CheckedRunnable} without an explicit cast or type * attribution at the call site. diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java deleted file mode 100644 index 627da8c91..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplier.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.function.Function; -import java.util.function.Supplier; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; - -/** - * Specialized {@link Supplier} that can throw any {@link Throwable}. - * - * @param The {@link Throwable} type - * @param The return type - * @see CheckedFn1 - * @see CheckedRunnable - */ -@FunctionalInterface -public interface CheckedSupplier extends Supplier, CheckedFn1 { - - /** - * A version of {@link Supplier#get()} that can throw checked exceptions. - * - * @return the supplied result - * @throws T any exception that can be thrown by this method - */ - A checkedGet() throws T; - - /** - * Convert this {@link CheckedSupplier} to a {@link CheckedRunnable}. - * - * @return the checked runnable - */ - default CheckedRunnable toRunnable() { - return this::get; - } - - @Override - default A checkedApply(Unit unit) throws T { - return checkedGet(); - } - - /** - * {@inheritDoc} - */ - @Override - default A get() { - try { - return checkedGet(); - } catch (Throwable t) { - throw throwChecked(t); - } - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier fmap(Function f) { - return CheckedFn1.super.fmap(f).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier flatMap(Function>> f) { - return CheckedFn1.super.flatMap(f).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier discardL(Applicative> appB) { - return CheckedFn1.super.discardL(appB).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier discardR(Applicative> appB) { - return CheckedFn1.super.discardR(appB).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier zip(Applicative, Fn1> appFn) { - return CheckedFn1.super.zip(appFn).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier zip(Fn2 appFn) { - return CheckedFn1.super.zip(appFn).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier diMapR(Function fn) { - return CheckedFn1.super.diMapR(fn).thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier> carry() { - return CheckedFn1.super.carry().thunk(UNIT)::apply; - } - - /** - * {@inheritDoc} - */ - @Override - default CheckedSupplier andThen(Function after) { - return CheckedFn1.super.andThen(after).thunk(UNIT)::apply; - } - - /** - * Convenience static factory method for constructing a {@link CheckedSupplier} without an explicit cast or type - * attribution at the call site. - * - * @param supplier the checked supplier - * @param the inferred Throwable type - * @param the supplier return type - * @return the checked supplier - */ - static CheckedSupplier checked(CheckedSupplier supplier) { - return supplier::get; - } -} diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 29c2e148b..d2e630e20 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -12,7 +13,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Function; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -22,7 +22,6 @@ 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 com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.CompletableFuture.supplyAsync; import static java.util.concurrent.ForkJoinPool.commonPool; @@ -180,20 +179,20 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { /** * Static factory method for coercing a lambda to an {@link IO}. * - * @param supplier the lambda to coerce - * @param the result type + * @param fn0 the lambda to coerce + * @param the result type * @return the {@link IO} */ - public static IO io(Supplier supplier) { + public static IO io(Fn0 fn0) { return new IO() { @Override public A unsafePerformIO() { - return supplier.get(); + return fn0.get(); } @Override public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return supplyAsync(supplier, executor); + return supplyAsync(fn0::apply, executor); } }; } @@ -220,11 +219,11 @@ public static IO io(Runnable runnable) { * @param the result type * @return the {@link IO} */ - public static IO externallyManaged(Supplier> supplier) { + public static IO externallyManaged(Fn0> supplier) { return new IO() { @Override public A unsafePerformIO() { - return checked(() -> unsafePerformAsyncIO().get()).get(); + return fn0(() -> unsafePerformAsyncIO().get()).apply(); } @Override diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java deleted file mode 100644 index 8472dc067..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffectTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static java.util.Arrays.asList; -import static org.junit.Assert.assertEquals; - -public class CheckedEffectTest { - - @Test - public void assignment() { - List results = new ArrayList<>(); - - CheckedEffect effect = results::add; - CheckedEffect diMapL = effect.diMapL(Object::toString); - CheckedEffect contraMap = effect.contraMap(Object::toString); - CheckedEffect compose = effect.compose(Object::toString); - CheckedEffect stringEffect = effect.discardR(constantly("1")); - CheckedEffect andThen = effect.andThen(effect); - - effect.accept("1"); - diMapL.accept("2"); - contraMap.accept("3"); - compose.accept("4"); - stringEffect.accept("5"); - andThen.accept("6"); - - assertEquals(asList("1", "2", "3", "4", "5", "6", "6"), results); - } -} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java deleted file mode 100644 index c5b614755..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedFn1Test.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import org.junit.Test; - -import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static org.junit.Assert.assertEquals; - -public class CheckedFn1Test { - - @Test - public void assignment() { - CheckedFn1 parseInt = Integer::parseInt; - CheckedFn1 fmap = parseInt.fmap(Object::toString); - CheckedFn1 flatMap = parseInt.flatMap(i -> constantly(i + "")); - CheckedFn1 discardL = parseInt.discardL(constantly("0")); - CheckedFn1 discardR = parseInt.discardR(constantly("0")); - CheckedFn1 zipApp = parseInt.zip(constantly(id())); - CheckedFn1 zipF = parseInt.zip(constantly()); - CheckedFn1 diMapL = parseInt.diMapL(id()); - CheckedFn1 diMapR = parseInt.diMapR(id()); - CheckedFn1 diMap = parseInt.diMap(id(), id()); - CheckedFn1, Tuple2> strengthen = parseInt.cartesian(); - CheckedFn1> carry = parseInt.carry(); - CheckedFn1 contraMap = parseInt.contraMap(id()); - CheckedFn1 compose = parseInt.compose(id()); - CheckedFn1 andThen = parseInt.andThen(id()); - - assertEquals((Integer) 1, parseInt.apply("1")); - assertEquals("1", fmap.apply("1")); - assertEquals("1", flatMap.apply("1")); - assertEquals("0", discardL.apply("1")); - assertEquals((Integer) 1, discardR.apply("1")); - assertEquals((Integer) 1, zipApp.apply("1")); - assertEquals("1", zipF.apply("1")); - assertEquals((Integer) 1, diMapL.apply("1")); - assertEquals((Integer) 1, diMapR.apply("1")); - assertEquals((Integer) 1, diMap.apply("1")); - assertEquals(tuple("foo", 1), strengthen.apply(tuple("foo", "1"))); - assertEquals(tuple("1", 1), carry.apply("1")); - assertEquals((Integer) 1, contraMap.apply("1")); - assertEquals((Integer) 1, compose.apply("1")); - assertEquals((Integer) 1, andThen.apply("1")); - } -} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java deleted file mode 100644 index 804b77ca0..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedSupplierTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.functions.builtin.fn1.Constantly; -import org.junit.Test; - -import static com.jnape.palatable.lambda.adt.Unit.UNIT; -import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; -import static org.junit.Assert.assertEquals; - -public class CheckedSupplierTest { - - @Test - public void assignment() { - CheckedSupplier intSupplier = checked(() -> 1); - CheckedSupplier fmap = intSupplier.fmap(Object::toString); - @SuppressWarnings("RedundantTypeArguments") - CheckedSupplier flatMap = intSupplier.flatMap(Constantly::constantly); - CheckedSupplier discardL = intSupplier.discardL(constantly(1)); - CheckedSupplier discardR = intSupplier.discardR(constantly(2)); - CheckedSupplier zipA = intSupplier.zip(constantly(id())); - CheckedSupplier zipF = intSupplier.zip(constantly()); - CheckedSupplier diMapR = intSupplier.diMapR(id()); - CheckedSupplier> carry = intSupplier.carry(); - CheckedSupplier andThen = intSupplier.andThen(id()); - - assertEquals((Integer) 1, intSupplier.get()); - assertEquals("1", fmap.get()); - assertEquals((Integer) 1, flatMap.get()); - assertEquals((Integer) 1, discardL.get()); - assertEquals((Integer) 1, discardR.get()); - assertEquals((Integer) 1, zipA.get()); - assertEquals(UNIT, zipF.get()); - assertEquals((Integer) 1, diMapR.get()); - assertEquals(tuple(UNIT, 1), carry.get()); - assertEquals((Integer) 1, andThen.get()); - } -} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 674bb8e8d..c6bd42b16 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -19,7 +19,6 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; -import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier.checked; import static com.jnape.palatable.lambda.io.IO.externallyManaged; import static com.jnape.palatable.lambda.io.IO.io; import static java.util.concurrent.CompletableFuture.completedFuture; @@ -55,23 +54,23 @@ public void unsafePerformAsyncIOWithExecutor() { @Test public void zipAndDerivativesComposesInParallel() { - String a = "foo"; + String a = "foo"; Fn1> f = tupler(1); - ExecutorService executor = newFixedThreadPool(2); - CountDownLatch advanceFirst = new CountDownLatch(1); - CountDownLatch advanceSecond = new CountDownLatch(1); + ExecutorService executor = newFixedThreadPool(2); + CountDownLatch advanceFirst = new CountDownLatch(1); + CountDownLatch advanceSecond = new CountDownLatch(1); - IO ioA = io(checked(() -> { + IO ioA = io(() -> { advanceFirst.countDown(); advanceSecond.await(); return a; - })); - IO>> ioF = io(checked(() -> { + }); + IO>> ioF = io(() -> { advanceFirst.await(); advanceSecond.countDown(); return f; - })); + }); IO> zip = ioA.zip(ioF); assertEquals(f.apply(a), zip.unsafePerformAsyncIO().join()); @@ -90,7 +89,7 @@ public void zipAndDerivativesComposesInParallel() { @Test public void delegatesToExternallyManagedFuture() { CompletableFuture future = completedFuture(1); - IO io = externallyManaged(() -> future); + IO io = externallyManaged(() -> future); assertEquals((Integer) 1, io.unsafePerformIO()); assertEquals((Integer) 1, io.unsafePerformAsyncIO().join()); assertEquals((Integer) 1, io.unsafePerformAsyncIO(commonPool()).join()); From 20e00f5de95fe234d4b11679d3e5497ebfe86895 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 6 May 2019 20:08:49 -0500 Subject: [PATCH 145/348] Deleting empty file --- .../lambda/functions/specialized/checked/CheckedEffect.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.java deleted file mode 100644 index e69de29bb..000000000 From eb596f80c34d473d7ab1dd0f2a96bff202b1860e Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 6 May 2019 20:22:47 -0500 Subject: [PATCH 146/348] Cutting all java.util.function/Runnable/Callable ties - Function replaced with Fn1 - BiFunction replaced with Fn2 - Supplier replaced with Fn0 - Consumer replaced with Effect - Runnable replaced with SideEffect in IO - j.u.f.Predicate replaced with Predicate - j.u.f.BiPredicate replaced with BiPredicate --- CHANGELOG.md | 12 +- .../jnape/palatable/lambda/adt/Either.java | 141 +++++++++--------- .../com/jnape/palatable/lambda/adt/Maybe.java | 48 +++--- .../com/jnape/palatable/lambda/adt/These.java | 41 ++--- .../com/jnape/palatable/lambda/adt/Try.java | 66 ++++---- .../palatable/lambda/adt/choice/Choice2.java | 32 ++-- .../palatable/lambda/adt/choice/Choice3.java | 44 +++--- .../palatable/lambda/adt/choice/Choice4.java | 52 +++---- .../palatable/lambda/adt/choice/Choice5.java | 67 ++++----- .../palatable/lambda/adt/choice/Choice6.java | 69 ++++----- .../palatable/lambda/adt/choice/Choice7.java | 97 ++++++------ .../palatable/lambda/adt/choice/Choice8.java | 105 ++++++------- .../lambda/adt/coproduct/CoProduct2.java | 17 +-- .../lambda/adt/coproduct/CoProduct3.java | 35 ++--- .../lambda/adt/coproduct/CoProduct4.java | 51 +++---- .../lambda/adt/coproduct/CoProduct5.java | 63 +++----- .../lambda/adt/coproduct/CoProduct6.java | 40 ++--- .../lambda/adt/coproduct/CoProduct7.java | 46 +++--- .../lambda/adt/coproduct/CoProduct8.java | 45 +++--- .../lambda/adt/hlist/SingletonHList.java | 19 +-- .../palatable/lambda/adt/hlist/Tuple2.java | 23 ++- .../palatable/lambda/adt/hlist/Tuple3.java | 24 +-- .../palatable/lambda/adt/hlist/Tuple4.java | 26 ++-- .../palatable/lambda/adt/hlist/Tuple5.java | 24 ++- .../palatable/lambda/adt/hlist/Tuple6.java | 24 ++- .../palatable/lambda/adt/hlist/Tuple7.java | 24 ++- .../palatable/lambda/adt/hlist/Tuple8.java | 24 ++- .../lambda/adt/product/Product2.java | 6 +- .../lambda/adt/product/Product3.java | 2 +- .../lambda/adt/product/Product4.java | 3 +- .../palatable/lambda/functions/Effect.java | 82 +++++----- .../jnape/palatable/lambda/functions/Fn0.java | 81 +++++----- .../jnape/palatable/lambda/functions/Fn1.java | 97 +++++------- .../jnape/palatable/lambda/functions/Fn2.java | 29 +--- .../jnape/palatable/lambda/functions/Fn3.java | 12 +- .../jnape/palatable/lambda/functions/Fn4.java | 12 +- .../jnape/palatable/lambda/functions/Fn5.java | 12 +- .../jnape/palatable/lambda/functions/Fn6.java | 12 +- .../jnape/palatable/lambda/functions/Fn7.java | 12 +- .../jnape/palatable/lambda/functions/Fn8.java | 13 +- .../lambda/functions/builtin/fn1/Empty.java | 2 +- .../lambda/functions/builtin/fn1/Inits.java | 2 +- .../functions/builtin/fn1/Magnetize.java | 2 +- .../lambda/functions/builtin/fn1/Not.java | 11 +- .../lambda/functions/builtin/fn2/All.java | 10 +- .../lambda/functions/builtin/fn2/Any.java | 11 +- .../lambda/functions/builtin/fn2/Both.java | 21 +-- .../functions/builtin/fn2/DropWhile.java | 10 +- .../lambda/functions/builtin/fn2/Filter.java | 10 +- .../lambda/functions/builtin/fn2/Find.java | 10 +- .../lambda/functions/builtin/fn2/GroupBy.java | 9 +- .../lambda/functions/builtin/fn2/Into.java | 13 +- .../lambda/functions/builtin/fn2/Into1.java | 14 +- .../lambda/functions/builtin/fn2/Into3.java | 2 +- .../lambda/functions/builtin/fn2/Iterate.java | 16 +- .../lambda/functions/builtin/fn2/LazyRec.java | 18 +-- .../functions/builtin/fn2/MagnetizeBy.java | 9 +- .../lambda/functions/builtin/fn2/Map.java | 10 +- .../functions/builtin/fn2/Partial2.java | 41 ----- .../functions/builtin/fn2/Partial3.java | 41 ----- .../functions/builtin/fn2/Partition.java | 9 +- .../lambda/functions/builtin/fn2/Peek.java | 18 +-- .../lambda/functions/builtin/fn2/Peek2.java | 30 ++-- .../functions/builtin/fn2/ReduceLeft.java | 11 +- .../functions/builtin/fn2/ReduceRight.java | 12 +- .../functions/builtin/fn2/Sequence.java | 30 ++-- .../lambda/functions/builtin/fn2/SortBy.java | 12 +- .../lambda/functions/builtin/fn2/Span.java | 12 +- .../functions/builtin/fn2/TakeWhile.java | 10 +- .../functions/builtin/fn2/ToCollection.java | 22 +-- .../lambda/functions/builtin/fn2/ToMap.java | 22 +-- .../lambda/functions/builtin/fn2/Unfoldr.java | 10 +- .../lambda/functions/builtin/fn2/Zip.java | 3 +- .../lambda/functions/builtin/fn3/CmpEqBy.java | 19 +-- .../functions/builtin/fn3/FoldLeft.java | 20 ++- .../functions/builtin/fn3/FoldRight.java | 22 ++- .../lambda/functions/builtin/fn3/GTBy.java | 19 +-- .../lambda/functions/builtin/fn3/GTEBy.java | 20 +-- .../lambda/functions/builtin/fn3/LTBy.java | 21 +-- .../lambda/functions/builtin/fn3/LTEBy.java | 19 ++- .../lambda/functions/builtin/fn3/LiftA2.java | 16 +- .../functions/builtin/fn3/ScanLeft.java | 25 ++-- .../lambda/functions/builtin/fn3/Times.java | 12 +- .../lambda/functions/builtin/fn3/ZipWith.java | 10 +- .../functions/builtin/fn4/IfThenElse.java | 29 ++-- .../functions/builtin/fn4/RateLimit.java | 43 +++--- .../functions/recursion/RecursiveResult.java | 27 ++-- .../functions/recursion/Trampoline.java | 18 +-- .../functions/specialized/BiPredicate.java | 66 ++++---- .../lambda/functions/specialized/Kleisli.java | 18 +-- .../lambda/functions/specialized/Noop.java | 8 +- .../functions/specialized/Predicate.java | 84 +++++++---- .../functions/specialized/SideEffect.java | 54 +++++++ .../specialized/checked/CheckedRunnable.java | 41 ----- .../palatable/lambda/functor/Applicative.java | 9 +- .../palatable/lambda/functor/Bifunctor.java | 8 +- .../lambda/functor/BoundedBifunctor.java | 16 +- .../palatable/lambda/functor/Cartesian.java | 11 +- .../palatable/lambda/functor/Cocartesian.java | 11 +- .../lambda/functor/Contravariant.java | 7 +- .../palatable/lambda/functor/Functor.java | 4 +- .../palatable/lambda/functor/Profunctor.java | 10 +- .../lambda/functor/builtin/Compose.java | 18 +-- .../lambda/functor/builtin/Const.java | 25 ++-- .../lambda/functor/builtin/Exchange.java | 29 ++-- .../lambda/functor/builtin/Identity.java | 16 +- .../lambda/functor/builtin/Lazy.java | 32 ++-- .../lambda/functor/builtin/Market.java | 28 ++-- .../lambda/functor/builtin/State.java | 10 +- .../lambda/functor/builtin/Tagged.java | 18 +-- .../com/jnape/palatable/lambda/io/IO.java | 49 +++--- .../lambda/iteration/ConsingIterator.java | 13 +- .../lambda/iteration/FilteringIterable.java | 13 +- .../lambda/iteration/FilteringIterator.java | 9 +- .../lambda/iteration/MappingIterable.java | 17 ++- .../lambda/iteration/MappingIterator.java | 9 +- .../iteration/PredicatedDroppingIterable.java | 14 +- .../iteration/PredicatedDroppingIterator.java | 11 +- .../iteration/PredicatedTakingIterable.java | 13 +- .../iteration/PredicatedTakingIterator.java | 12 +- .../iteration/RateLimitingIterable.java | 9 +- .../iteration/RateLimitingIterator.java | 20 +-- .../lambda/iteration/ScanningIterator.java | 11 +- .../lambda/iteration/UnfoldingIterator.java | 14 +- .../lambda/iteration/ZippingIterator.java | 11 +- .../jnape/palatable/lambda/monad/Monad.java | 19 ++- .../lambda/monad/transformer/MonadT.java | 13 +- .../monad/transformer/builtin/EitherT.java | 16 +- .../monad/transformer/builtin/IdentityT.java | 15 +- .../monad/transformer/builtin/LazyT.java | 18 +-- .../monad/transformer/builtin/MaybeT.java | 13 +- .../jnape/palatable/lambda/monoid/Monoid.java | 15 +- .../lambda/monoid/builtin/AddAll.java | 23 ++- .../palatable/lambda/monoid/builtin/And.java | 9 +- .../lambda/monoid/builtin/Compose.java | 4 +- .../lambda/monoid/builtin/Concat.java | 3 +- .../lambda/monoid/builtin/First.java | 4 +- .../lambda/monoid/builtin/MergeMaps.java | 26 ++-- .../palatable/lambda/monoid/builtin/Or.java | 9 +- .../palatable/lambda/monoid/builtin/Xor.java | 5 - .../jnape/palatable/lambda/optics/Iso.java | 39 +++-- .../jnape/palatable/lambda/optics/Lens.java | 37 +++-- .../jnape/palatable/lambda/optics/Optic.java | 15 +- .../jnape/palatable/lambda/optics/Prism.java | 13 +- .../lambda/optics/functions/Over.java | 12 +- .../lambda/optics/functions/Under.java | 14 +- .../lambda/optics/lenses/CollectionLens.java | 9 +- .../lambda/optics/lenses/IterableLens.java | 2 +- .../lambda/optics/lenses/MapLens.java | 26 ++-- .../lambda/optics/lenses/SetLens.java | 51 ++++++- .../palatable/lambda/semigroup/Semigroup.java | 2 +- .../lambda/semigroup/builtin/Absent.java | 2 +- .../lambda/semigroup/builtin/MaxBy.java | 13 +- .../lambda/semigroup/builtin/MinBy.java | 13 +- .../lambda/semigroup/builtin/RightAny.java | 2 +- .../lambda/traversable/LambdaIterable.java | 16 +- .../lambda/traversable/LambdaMap.java | 19 ++- .../lambda/traversable/Traversable.java | 11 +- .../palatable/lambda/adt/EitherTest.java | 47 +++--- .../jnape/palatable/lambda/adt/MaybeTest.java | 5 +- .../lambda/adt/choice/Choice6Test.java | 5 +- .../lambda/adt/choice/Choice7Test.java | 5 +- .../lambda/adt/choice/Choice8Test.java | 6 +- .../lambda/adt/coproduct/CoProduct2Test.java | 7 +- .../lambda/adt/coproduct/CoProduct3Test.java | 17 +-- .../lambda/adt/coproduct/CoProduct4Test.java | 30 ++-- .../lambda/adt/coproduct/CoProduct5Test.java | 47 +++--- .../lambda/adt/coproduct/CoProduct6Test.java | 41 +++-- .../lambda/adt/coproduct/CoProduct7Test.java | 61 ++++---- .../lambda/adt/coproduct/CoProduct8Test.java | 69 +++++---- .../lambda/adt/hlist/Tuple2Test.java | 11 +- .../lambda/adt/hlist/Tuple3Test.java | 9 +- .../lambda/adt/hlist/Tuple4Test.java | 13 +- .../lambda/adt/hlist/Tuple5Test.java | 15 +- .../lambda/adt/hlist/Tuple6Test.java | 15 +- .../lambda/adt/hlist/Tuple7Test.java | 15 +- .../lambda/adt/hlist/Tuple8Test.java | 19 ++- .../lambda/functions/EffectTest.java | 31 ++-- .../palatable/lambda/functions/Fn0Test.java | 39 +++++ .../palatable/lambda/functions/Fn1Test.java | 18 ++- .../palatable/lambda/functions/Fn2Test.java | 15 +- .../functions/builtin/fn1/FlattenTest.java | 2 +- .../lambda/functions/builtin/fn2/AllTest.java | 4 +- .../functions/builtin/fn2/AlterTest.java | 3 +- .../lambda/functions/builtin/fn2/AnyTest.java | 4 +- .../builtin/fn2/MagnetizeByTest.java | 12 +- .../functions/builtin/fn2/Partial2Test.java | 18 --- .../functions/builtin/fn2/Partial3Test.java | 18 --- .../functions/builtin/fn2/PartitionTest.java | 4 +- .../functions/builtin/fn2/Peek2Test.java | 14 +- .../functions/builtin/fn2/PeekTest.java | 5 +- .../functions/builtin/fn2/SequenceTest.java | 7 +- .../builtin/fn2/ToCollectionTest.java | 5 +- .../functions/builtin/fn3/LiftA2Test.java | 7 +- .../functions/builtin/fn3/ZipWithTest.java | 10 +- .../functions/builtin/fn4/RateLimitTest.java | 5 +- .../functions/recursion/TrampolineTest.java | 5 +- .../specialized/BiPredicateTest.java | 46 ++++-- .../functions/specialized/PredicateTest.java | 56 ++++--- .../functions/specialized/SideEffectTest.java | 28 ++++ .../lambda/functor/BifunctorTest.java | 6 +- .../lambda/functor/ProfunctorTest.java | 6 +- .../com/jnape/palatable/lambda/io/IOTest.java | 5 +- .../iteration/ScanningIteratorTest.java | 4 +- .../lambda/iteration/ZippingIteratorTest.java | 8 +- .../palatable/lambda/optics/PrismTest.java | 6 +- .../traversable/LambdaIterableTest.java | 7 +- src/test/java/testsupport/EquatableM.java | 18 +-- .../InvocationRecordingBifunctor.java | 13 +- .../InvocationRecordingProfunctor.java | 14 +- .../testsupport/functions/ExplainFold.java | 4 +- .../testsupport/matchers/LeftMatcher.java | 7 +- .../testsupport/matchers/RightMatcher.java | 7 +- .../testsupport/traits/ApplicativeLaws.java | 41 ++--- .../testsupport/traits/BifunctorLaws.java | 5 +- .../java/testsupport/traits/FunctorLaws.java | 17 ++- .../java/testsupport/traits/MonadLaws.java | 12 +- .../testsupport/traits/TraversableLaws.java | 28 ++-- 218 files changed, 2218 insertions(+), 2434 deletions(-) delete mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java delete mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java delete mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java delete mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2Test.java delete mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3Test.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/specialized/SideEffectTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index bad86b559..76b7ca7cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). factory methods should continue to work (by simply targeting `Supplier` now instead of an anonymous `IO`), but some might need to be reworked, and subtyping is obviously no longer supported. +- ***Breaking Change***: Breaking all dependency on `java.util.function` types across the board. All `Fn*` types target + methods now support throwing `Throwable`; `apply` is now defaulted and will simply bypass javac + to throw checked exceptions as if they were unchecked. All `Checked` variants have been + eliminated as a consequence, as they are no longer necessary. Also, straggler functions like + `Partial2/3` that only existed to aid in partial application of non-curried functions are now + superfluous, and have also been eliminated. - ***Breaking Change***: `FoldRight` now requires `Lazy` as part of its interface to support short-circuiting operations - ***Breaking Change***: Eliminated all raw types and java11 warnings. This required using capture in unification parameters for Functor and friends, so nearly every functor's type-signature changed. @@ -17,11 +23,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). type is now the supertype of `Lens` and `Iso`, and `lens` package has been moved to `optics` - ***Breaking Change***: `Try` and `Either` no longer preserve `Throwable` type since it was inherently not type-safe anyway; Try is therefore no longer a `Bifunctor`, and `orThrow` can be used to declare checked - exceptions that could be caught by corresponding catch blocks -- ***Breaking Change***: All `Fn*` types target methods now support throwing `Throwable`; `apply` is now defaulted and - will simply bypass javac to throw checked exceptions as if they were unchecked. This allows all - checked variants to be eliminated -- ***Breaking Change***: All `Checked` variants have been eliminated + exceptions that could be caught by corresponding catch blocks - `IO` is now stack-safe, regardless of whether the composition nests linearly or recursively ### Added 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 e6c0aeebb..1148c0523 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -2,12 +2,13 @@ import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; -import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek2; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable; +import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -15,10 +16,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; @@ -59,7 +56,7 @@ public final R or(R defaultValue) { * @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(Function recoveryFn) { + public final R recover(Fn1 recoveryFn) { return match(recoveryFn, id()); } @@ -70,7 +67,7 @@ public final R recover(Function recoveryFn) { * @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(Function forfeitFn) { + public final L forfeit(Fn1 forfeitFn) { return match(id(), forfeitFn); } @@ -78,13 +75,13 @@ public final L forfeit(Function forfeitFn) { * Return the wrapped value if this is a right; otherwise, map the wrapped left value to a T and throw * it. * - * @param throwableFn a function from L to T * @param the left parameter type (the throwable type) + * @param throwableFn a function from L to T * @return the wrapped value if this is a right * @throws T the result of applying the wrapped left value to throwableFn, if this is a left */ - public final R orThrow(Function throwableFn) throws T { - return match((Fn1) l -> { + public final R orThrow(Fn1 throwableFn) throws T { + return match(l -> { throw throwableFn.apply(l); }, id()); } @@ -95,13 +92,13 @@ public final R orThrow(Function th *

* 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 + * @param pred the predicate to apply to a right value + * @param leftFn0 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(Function pred, Supplier leftSupplier) { - return filter(pred, __ -> leftSupplier.get()); + public final Either filter(Fn1 pred, Fn0 leftFn0) { + return filter(pred, __ -> leftFn0.apply()); } /** @@ -113,8 +110,8 @@ public final Either filter(Function pred, Su * @return this is a left value or a right value that pred matches; otherwise, the result of leftFn applied to the * right value, wrapped in a left */ - public final Either filter(Function pred, - Function leftFn) { + public final Either filter(Fn1 pred, + Fn1 leftFn) { return flatMap(r -> pred.apply(r) ? right(r) : left(leftFn.apply(r))); } @@ -131,8 +128,8 @@ public final Either filter(Function pred, */ @Override @SuppressWarnings("RedundantTypeArguments") - public Either flatMap(Function>> rightFn) { - return match(Either::left, rightFn.andThen(Monad>::coerce)); + public Either flatMap(Fn1>> rightFn) { + return match(Either::left, rightFn.fmap(Monad>::coerce)); } @Override @@ -153,8 +150,8 @@ public final Either invert() { */ @SafeVarargs @SuppressWarnings("varargs") - public final Either merge(BiFunction leftFn, - BiFunction rightFn, + public final Either merge(Fn2 leftFn, + Fn2 rightFn, Either... others) { return foldLeft((x, y) -> x.match(l1 -> y.match(l2 -> left(leftFn.apply(l1, l2)), r -> left(l1)), r1 -> y.match(Either::left, r2 -> right(rightFn.apply(r1, r2)))), @@ -165,22 +162,22 @@ public final Either merge(BiFunction le /** * Perform side-effects against a wrapped right value, returning back the Either unaltered. * - * @param rightConsumer the effecting consumer + * @param effect the effecting consumer * @return the Either, unaltered */ - public Either peek(Consumer rightConsumer) { - return Peek.peek(rightConsumer, this); + public Either peek(Effect effect) { + return Peek.peek(effect, this); } /** * 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 + * @param leftEffect the effecting consumer for left values + * @param rightEffect the effecting consumer for right values * @return the Either, unaltered */ - public Either peek(Consumer leftConsumer, Consumer rightConsumer) { - return Peek2.peek2(leftConsumer, rightConsumer, this); + public Either peek(Effect leftEffect, Effect rightEffect) { + return Peek2.peek2(leftEffect, rightEffect, this); } /** @@ -188,13 +185,13 @@ public Either peek(Consumer leftConsumer, Consumer rightConsumer) { * V), unwrap the value stored in this Either, apply the appropriate mapping function, * and return the result. * + * @param the result type * @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 */ @Override - public abstract V match(Function leftFn, Function rightFn); + public abstract V match(Fn1 leftFn, Fn1 rightFn); /** * {@inheritDoc} @@ -208,7 +205,7 @@ public Choice3 diverge() { * {@inheritDoc} */ @Override - public final Either fmap(Function fn) { + public final Either fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -216,26 +213,24 @@ public final Either fmap(Function fn) { * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public final Either biMapL(Function fn) { - return (Either) Bifunctor.super.biMapL(fn); + public final Either biMapL(Fn1 fn) { + return (Either) Bifunctor.super.biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public final Either biMapR(Function fn) { - return (Either) Bifunctor.super.biMapR(fn); + public final Either biMapR(Fn1 fn) { + return (Either) Bifunctor.super.biMapR(fn); } /** * {@inheritDoc} */ @Override - public final Either biMap(Function leftFn, - Function rightFn) { + public final Either biMap(Fn1 leftFn, + Fn1 rightFn) { return match(l -> left(leftFn.apply(l)), r -> right(rightFn.apply(r))); } @@ -251,8 +246,8 @@ public final Either pure(R2 r2) { * {@inheritDoc} */ @Override - public final Either zip(Applicative, Either> appFn) { - return appFn.>>coerce().flatMap(this::biMapR); + public final Either zip(Applicative, Either> appFn) { + return Monad.super.zip(appFn).coerce(); } /** @@ -260,7 +255,7 @@ public final Either zip(Applicative Lazy> lazyZip( - Lazy, Either>> lazyAppFn) { + Lazy, Either>> lazyAppFn) { return match(l -> lazy(left(l)), r -> lazyAppFn.fmap(eitherLF -> eitherLF.fmap(f -> f.apply(r)).coerce())); } @@ -288,8 +283,8 @@ public final Either discardR(Applicative> appB) { @SuppressWarnings("unchecked") public final , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return (AppTrav) match(l -> pure.apply((TravB) left(l)), r -> fn.apply(r).fmap(Either::right)); } @@ -307,67 +302,65 @@ public final Maybe toMaybe() { * Convert a {@link Maybe}<R> into an Either<L, R>, supplying the left value from * leftFn in the case of {@link Maybe#nothing()}. * - * @param maybe the maybe - * @param leftFn the supplier to use for left values - * @param the left parameter type - * @param the right parameter type + * @param the left parameter type + * @param the right parameter type + * @param maybe the maybe + * @param leftFn0 the supplier to use for left values * @return a right value of the contained maybe value, or a left value of leftFn's result */ - public static Either fromMaybe(Maybe maybe, Supplier leftFn) { + public static Either fromMaybe(Maybe maybe, Fn0 leftFn0) { return maybe.>fmap(Either::right) - .orElseGet(() -> left(leftFn.get())); + .orElseGet(() -> left(leftFn0.apply())); } /** * Attempt to execute the {@link Fn0}, 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 left parameter type - * @param the right parameter type + * @param the left parameter type + * @param the right parameter type + * @param fn0 the supplier of the right value + * @param leftFn a function mapping E to L * @return the supplier result as a right value, or leftFn's mapping result as a left value */ - public static Either trying(Fn0 supplier, - Function leftFn) { - return Try.trying(supplier::get).toEither(leftFn); + public static Either trying(Fn0 fn0, Fn1 leftFn) { + return Try.trying(fn0).toEither(leftFn); } /** * Attempt to execute the {@link Fn0}, returning its result in a right value. If the supplier throws an * exception, wrap it in a left value and return it. * - * @param supplier the supplier of the right value - * @param the right parameter type + * @param fn0 the supplier of the right value + * @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(Fn0 supplier) { - return trying(supplier, id()); + public static Either trying(Fn0 fn0) { + return trying(fn0, id()); } /** - * Attempt to execute the {@link CheckedRunnable}, returning {@link Unit} in a right value. If the runnable throws + * Attempt to execute the {@link SideEffect}, returning {@link Unit} in a right value. If the runnable throws * an exception, apply leftFn to it, wrap it in a left value, and return it. * - * @param runnable the runnable - * @param leftFn a function mapping E to L - * @param the left parameter type + * @param the left parameter type + * @param sideEffect the runnable + * @param leftFn a function mapping E to L * @return {@link Unit} as a right value, or leftFn's mapping result as a left value */ - public static Either trying(CheckedRunnable runnable, - Function leftFn) { - return Try.trying(runnable).toEither(leftFn); + public static Either trying(SideEffect sideEffect, Fn1 leftFn) { + return Try.trying(sideEffect).toEither(leftFn); } /** - * Attempt to execute the {@link CheckedRunnable}, returning {@link Unit} in a right value. If the runnable throws + * Attempt to execute the {@link SideEffect}, returning {@link Unit} in a right value. If the runnable throws * exception, wrap it in a left value and return it. * - * @param runnable the runnable + * @param sideEffect the runnable * @return {@link Unit} as a right value, or a left value of the thrown exception */ - public static Either trying(CheckedRunnable runnable) { - return trying(runnable, id()); + public static Either trying(SideEffect sideEffect) { + return trying(sideEffect, id()); } /** @@ -402,7 +395,7 @@ private Left(L l) { } @Override - public V match(Function leftFn, Function rightFn) { + public V match(Fn1 leftFn, Fn1 rightFn) { return leftFn.apply(l); } @@ -432,7 +425,7 @@ private Right(R r) { } @Override - public V match(Function leftFn, Function rightFn) { + public V match(Fn1 leftFn, Fn1 rightFn) { return rightFn.apply(r); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index 892edc8ab..94f4e6bda 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -5,7 +5,9 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; @@ -15,9 +17,6 @@ import java.util.Objects; import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Unit.UNIT; @@ -44,11 +43,11 @@ private Maybe() { /** * If the value is present, return it; otherwise, return the value supplied by otherSupplier. * - * @param otherSupplier the supplier for the other value + * @param otherFn0 the supplier for the other value * @return this value, or the supplied other value */ - public final A orElseGet(Supplier otherSupplier) { - return match(__ -> otherSupplier.get(), id()); + public final A orElseGet(Fn0 otherFn0) { + return match(__ -> otherFn0.apply(), id()); } /** @@ -72,7 +71,7 @@ public final A orElse(A other) { */ public final A orElseThrow(Fn0 throwableSupplier) throws E { return orElseGet(fn0(() -> { - throw throwableSupplier.get(); + throw throwableSupplier.apply(); })); } @@ -83,7 +82,7 @@ public final A orElseThrow(Fn0 throwableSuppl * @param predicate the predicate to apply to the possibly absent value * @return maybe the present value that satisfied the predicate */ - public final Maybe filter(Function predicate) { + public final Maybe filter(Fn1 predicate) { return flatMap(a -> predicate.apply(a) ? just(a) : nothing()); } @@ -91,12 +90,12 @@ public final Maybe filter(Function predicate) { * If this value is absent, return the value supplied by lSupplier wrapped in Either.left. * Otherwise, wrap the value in Either.right and return it. * - * @param lSupplier the supplier for the left value - * @param the left parameter type + * @param the left parameter type + * @param lFn0 the supplier for the left value * @return this value wrapped in an Either.right, or an Either.left around the result of lSupplier */ - public final Either toEither(Supplier lSupplier) { - return fmap(Either::right).orElseGet(() -> left(lSupplier.get())); + public final Either toEither(Fn0 lFn0) { + return fmap(Either::right).orElseGet(() -> left(lFn0.apply())); } /** @@ -127,7 +126,7 @@ public final Maybe pure(B b) { * {@link Maybe#nothing}. */ @Override - public final Maybe fmap(Function fn) { + public final Maybe fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -135,7 +134,7 @@ public final Maybe fmap(Function fn) { * {@inheritDoc} */ @Override - public final Maybe zip(Applicative, Maybe> appFn) { + public final Maybe zip(Applicative, Maybe> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -147,8 +146,7 @@ public final Maybe zip(Applicative, Mayb * @return the zipped {@link Maybe} */ @Override - public Lazy> lazyZip( - Lazy, Maybe>> lazyAppFn) { + public Lazy> lazyZip(Lazy, Maybe>> lazyAppFn) { return match(constantly(lazy(nothing())), a -> lazyAppFn.fmap(maybeF -> maybeF.fmap(f -> f.apply(a)).coerce())); } @@ -174,8 +172,8 @@ public final Maybe discardR(Applicative> appB) { */ @SuppressWarnings("RedundantTypeArguments") @Override - public final Maybe flatMap(Function>> f) { - return match(constantly(nothing()), f.andThen(Monad>::coerce)); + public final Maybe flatMap(Fn1>> f) { + return match(constantly(nothing()), f.fmap(Monad>::coerce)); } /** @@ -205,19 +203,19 @@ public Choice2 invert() { /** * If this value is present, accept it by consumer; otherwise, do nothing. * - * @param consumer the consumer + * @param effect the consumer * @return the same Maybe instance */ - public final Maybe peek(Consumer consumer) { - return Peek.peek(consumer, this); + public final Maybe peek(Effect effect) { + return Peek.peek(effect, this); } @Override @SuppressWarnings("unchecked") public final , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(__ -> pure.apply((TravB) Maybe.nothing()), a -> (AppTrav) fn.apply(a).fmap(Maybe::just)); } @@ -289,7 +287,7 @@ private Nothing() { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return aFn.apply(UNIT); } @@ -308,7 +306,7 @@ private Just(A a) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return bFn.apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index 4416135de..039b149fd 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.coproduct.CoProduct3; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -10,7 +11,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -25,7 +25,11 @@ * @param the first possible type * @param the second possible type */ -public abstract class These implements CoProduct3, These>, Monad>, Bifunctor>, Traversable> { +public abstract class These implements + CoProduct3, These>, + Monad>, + Bifunctor>, + Traversable> { private These() { } @@ -34,8 +38,8 @@ private These() { * {@inheritDoc} */ @Override - public final These biMap(Function lFn, - Function rFn) { + public final These biMap(Fn1 lFn, + Fn1 rFn) { return match(a -> a(lFn.apply(a)), b -> b(rFn.apply(b)), into((a, b) -> both(lFn.apply(a), rFn.apply(b)))); } @@ -43,7 +47,7 @@ public final These biMap(Function lFn, * {@inheritDoc} */ @Override - public final These flatMap(Function>> f) { + public final These flatMap(Fn1>> f) { return match(These::a, b -> f.apply(b).coerce(), into((a, b) -> f.apply(b).>coerce().biMapL(constantly(a)))); } @@ -58,9 +62,8 @@ public final These pure(C c) { @Override @SuppressWarnings("unchecked") public , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppB extends Applicative, AppTrav extends Applicative> + AppTrav traverse(Fn1 fn, Fn1 pure) { return match(a -> pure.apply((TravB) a(a)), b -> fn.apply(b).fmap(this::pure).fmap(Applicative::coerce).coerce(), into((a, b) -> fn.apply(b).fmap(c -> both(a, c)).fmap(Applicative::coerce).coerce())); @@ -71,7 +74,7 @@ AppTrav extends Applicative> AppTrav traverse(Function These biMapL(Function fn) { + public final These biMapL(Fn1 fn) { return (These) Bifunctor.super.biMapL(fn); } @@ -80,7 +83,7 @@ public final These biMapL(Function fn) { */ @Override @SuppressWarnings("unchecked") - public final These biMapR(Function fn) { + public final These biMapR(Fn1 fn) { return (These) Bifunctor.super.biMapR(fn); } @@ -88,7 +91,7 @@ public final These biMapR(Function fn) { * {@inheritDoc} */ @Override - public final These fmap(Function fn) { + public final These fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -96,13 +99,13 @@ public final These fmap(Function fn) { * {@inheritDoc} */ @Override - public final These zip(Applicative, These> appFn) { + public final These zip(Applicative, These> appFn) { return Monad.super.zip(appFn).coerce(); } @Override public Lazy> lazyZip( - Lazy, These>> lazyAppFn) { + Lazy, These>> lazyAppFn) { return projectA().>>fmap(a -> lazy(a(a))) .orElseGet(() -> Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce)); } @@ -170,8 +173,8 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function, ? extends R> cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1, ? extends R> cFn) { return aFn.apply(a); } @@ -199,8 +202,8 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function, ? extends R> cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1, ? extends R> cFn) { return bFn.apply(b); } @@ -228,8 +231,8 @@ private Both(Tuple2 tuple) { } @Override - public R match(Function aFn, Function bFn, - Function, ? extends R> cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1, ? extends R> cFn) { return cFn.apply(both); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index bec29194a..3aeacead1 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -3,15 +3,15 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable; +import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.Unit.UNIT; @@ -35,14 +35,14 @@ private Try() { /** * Catch any instance of throwableType and map it to a success value. * + * @param the {@link Throwable} (sub)type * @param throwableType the {@link Throwable} (sub)type to be caught * @param recoveryFn the function mapping the {@link Throwable} to the result - * @param the {@link Throwable} (sub)type * @return a new {@link Try} instance around either the original successful result or the mapped result */ @SuppressWarnings("unchecked") public final Try catching(Class throwableType, - Function recoveryFn) { + Fn1 recoveryFn) { return catching(throwableType::isInstance, t -> recoveryFn.apply((S) t)); } @@ -53,8 +53,8 @@ public final Try catching(Class throwableType, * @param recoveryFn the function mapping the {@link Throwable} to the result * @return a new {@link Try} instance around either the original successful result or the mapped result */ - public final Try catching(Function predicate, - Function recoveryFn) { + public final Try catching(Fn1 predicate, + Fn1 recoveryFn) { return match(t -> predicate.apply(t) ? success(recoveryFn.apply(t)) : failure(t), Try::success); } @@ -67,18 +67,18 @@ public final Try catching(Function pred * over some {@link Throwable} t1, and the runnable throws a new {@link Throwable} t2, the * result is a failure over t1 with t2 added to t1 as a suppressed exception. * - * @param runnable the runnable block of code to execute + * @param sideEffect the runnable block of code to execute * @return the same {@link Try} instance if runnable completes successfully; otherwise, a {@link Try} conforming to * rules above */ - public final Try ensuring(CheckedRunnable runnable) { - return match(t -> trying(runnable) + public final Try ensuring(SideEffect sideEffect) { + return match(t -> trying(sideEffect) .>fmap(constantly(failure(t))) .recover(t2 -> { t.addSuppressed(t2); return failure(t); }), - a -> trying(runnable).fmap(constantly(a))); + a -> trying(sideEffect).fmap(constantly(a))); } /** @@ -88,7 +88,7 @@ public final Try ensuring(CheckedRunnable runnable) { * @param fn the function mapping the potential {@link Throwable} T to A * @return a success value */ - public final A recover(Function fn) { + public final A recover(Fn1 fn) { return match(fn, id()); } @@ -99,14 +99,16 @@ public final A recover(Function fn) { * @param fn the function mapping the potential A to T * @return a failure value */ - public final Throwable forfeit(Function fn) { + public final Throwable forfeit(Fn1 fn) { return match(id(), fn); } /** * If this is a success value, return it. Otherwise, rethrow the captured failure. * + * @param a declarable exception type used for catching checked exceptions * @return possibly the success value + * @throws T anything that the call site may want to explicitly catch or indicate could be thrown */ public abstract A orThrow() throws T; @@ -134,19 +136,19 @@ public final Either toEither() { * If this is a success, wrap the value in a {@link Either#right} and return it. Otherwise, apply the mapping * function to the failure {@link Throwable}, re-wrap it in an {@link Either#left}, and return it. * - * @param fn the mapping function * @param the {@link Either} left parameter type + * @param fn the mapping function * @return {@link Either} the success value or the mapped left value */ - public final Either toEither(Function fn) { - return match(fn.andThen(Either::left), Either::right); + public final Either toEither(Fn1 fn) { + return match(fn.fmap(Either::left), Either::right); } /** * {@inheritDoc} */ @Override - public Try fmap(Function fn) { + public Try fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -154,7 +156,7 @@ public Try fmap(Function fn) { * {@inheritDoc} */ @Override - public Try flatMap(Function>> f) { + public Try flatMap(Fn1>> f) { return match(Try::failure, a -> f.apply(a).coerce()); } @@ -170,13 +172,15 @@ public Try pure(B b) { * {@inheritDoc} */ @Override - public Try zip(Applicative, Try> appFn) { + public Try zip(Applicative, Try> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override - public Lazy> lazyZip( - Lazy, Try>> lazyAppFn) { + public Lazy> lazyZip(Lazy, Try>> lazyAppFn) { return match(f -> lazy(failure(f)), s -> lazyAppFn.fmap(tryF -> tryF.fmap(f -> f.apply(s)).coerce())); } @@ -204,8 +208,8 @@ public Try discardR(Applicative> appB) { @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(t -> pure.apply((TravB) failure(t)), a -> fn.apply(a).fmap(Try::success).fmap(Applicative::coerce).coerce()); } @@ -242,7 +246,7 @@ public static Try failure(T t) { */ public static Try trying(Fn0 supplier) { try { - return success(supplier.get()); + return success(supplier.apply()); } catch (Throwable t) { return failure(t); } @@ -251,20 +255,20 @@ public static Try trying(Fn0 supplier) { /** * Execute runnable, returning a success {@link Unit} or a failure of the thrown {@link Throwable}. * - * @param runnable the runnable + * @param sideEffect the runnable * @return a new {@link Try} around either a successful {@link Unit} result or the thrown {@link Throwable} */ - public static Try trying(CheckedRunnable runnable) { + public static Try trying(SideEffect sideEffect) { return trying(() -> { - runnable.run(); + IO.io(sideEffect).unsafePerformIO(); return UNIT; }); } /** - * Given a {@link Fn0}<{@link AutoCloseable}> aSupplier and a - * {@link Function} fn, apply fn to the result of aSupplier, ensuring - * that the result has its {@link AutoCloseable#close() close} method invoked, regardless of the outcome. + * Given a {@link Fn0}<{@link AutoCloseable}> aSupplier and an {@link Fn1} + * fn, apply fn to the result of aSupplier, ensuring that the result has its + * {@link AutoCloseable#close() close} method invoked, regardless of the outcome. *

* If the resource creation process throws, the function body throws, or the * {@link AutoCloseable#close() close method} throws, the result is a failure. If both the function body and the @@ -354,7 +358,7 @@ public A orThrow() { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return aFn.apply(t); } @@ -389,7 +393,7 @@ public A orThrow() { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return bFn.apply(a); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index d056ae87c..24cc10bc5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.Functor; @@ -13,7 +14,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -66,7 +66,7 @@ public Choice2 invert() { * {@inheritDoc} */ @Override - public final Choice2 fmap(Function fn) { + public final Choice2 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -74,26 +74,24 @@ public final Choice2 fmap(Function fn) { * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public final Choice2 biMapL(Function fn) { - return (Choice2) Bifunctor.super.biMapL(fn); + public final Choice2 biMapL(Fn1 fn) { + return (Choice2) Bifunctor.super.biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public final Choice2 biMapR(Function fn) { - return (Choice2) Bifunctor.super.biMapR(fn); + public final Choice2 biMapR(Fn1 fn) { + return (Choice2) Bifunctor.super.biMapR(fn); } /** * {@inheritDoc} */ @Override - public final Choice2 biMap(Function lFn, - Function rFn) { + public final Choice2 biMap(Fn1 lFn, + Fn1 rFn) { return match(a -> a(lFn.apply(a)), b -> b(rFn.apply(b))); } @@ -109,7 +107,7 @@ public Choice2 pure(C c) { * {@inheritDoc} */ @Override - public Choice2 zip(Applicative, Choice2> appFn) { + public Choice2 zip(Applicative, Choice2> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -118,7 +116,7 @@ public Choice2 zip(Applicative, Choic */ @Override public Lazy>> lazyZip( - Lazy, Choice2>> lazyAppFn) { + Lazy, Choice2>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(b)).coerce())); } @@ -143,7 +141,7 @@ public Choice2 discardR(Applicative> appB) { * {@inheritDoc} */ @Override - public final Choice2 flatMap(Function>> f) { + public final Choice2 flatMap(Fn1>> f) { return match(Choice2::a, b -> f.apply(b).coerce()); } @@ -154,8 +152,8 @@ public final Choice2 flatMap(Function, TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(a -> pure.apply((TravB) a(a)), b -> fn.apply(b).>fmap(Choice2::b).fmap(Functor::coerce).coerce()); } @@ -193,7 +191,7 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return aFn.apply(a); } @@ -225,7 +223,7 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return bFn.apply(b); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 0ba9eddc4..0b58ca14f 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct3; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple3; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.Functor; @@ -13,7 +14,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into3.into3; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -58,15 +58,15 @@ public final Choice4 diverge() { * {@inheritDoc} */ @Override - public final Choice2 converge(Function> convergenceFn) { - return match(Choice2::a, Choice2::b, convergenceFn.andThen(cp2 -> cp2.match(Choice2::a, Choice2::b))); + public final Choice2 converge(Fn1> convergenceFn) { + return match(Choice2::a, Choice2::b, convergenceFn.fmap(cp2 -> cp2.match(Choice2::a, Choice2::b))); } /** * {@inheritDoc} */ @Override - public final Choice3 fmap(Function fn) { + public final Choice3 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -74,26 +74,24 @@ public final Choice3 fmap(Function fn) { * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public final Choice3 biMapL(Function fn) { - return (Choice3) Bifunctor.super.biMapL(fn); + public final Choice3 biMapL(Fn1 fn) { + return (Choice3) Bifunctor.super.biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public final Choice3 biMapR(Function fn) { - return (Choice3) Bifunctor.super.biMapR(fn); + public final Choice3 biMapR(Fn1 fn) { + return (Choice3) Bifunctor.super.biMapR(fn); } /** * {@inheritDoc} */ @Override - public final Choice3 biMap(Function lFn, - Function rFn) { + public final Choice3 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice3::a, b -> b(lFn.apply(b)), c -> c(rFn.apply(c))); } @@ -109,7 +107,7 @@ public Choice3 pure(D d) { * {@inheritDoc} */ @Override - public Choice3 zip(Applicative, Choice3> appFn) { + public Choice3 zip(Applicative, Choice3> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -118,7 +116,7 @@ public Choice3 zip(Applicative, Ch */ @Override public Lazy> lazyZip( - Lazy, Choice3>> lazyAppFn) { + Lazy, Choice3>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(c)).coerce())); @@ -144,7 +142,7 @@ public Choice3 discardR(Applicative> appB) { * {@inheritDoc} */ @Override - public Choice3 flatMap(Function>> f) { + public Choice3 flatMap(Fn1>> f) { return match(Choice3::a, Choice3::b, c -> f.apply(c).coerce()); } @@ -155,8 +153,8 @@ public Choice3 flatMap(Function, TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice3.a(a)).coerce(), b -> pure.apply((TravB) Choice3.b(b)).coerce(), c -> fn.apply(c).>fmap(Choice3::c).fmap(Functor::coerce).coerce()); @@ -210,8 +208,8 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return aFn.apply(a); } @@ -243,8 +241,8 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return bFn.apply(b); } @@ -276,8 +274,8 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return cFn.apply(c); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index f24a04042..a93eae6cd 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct4; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple4; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.Functor; @@ -13,7 +14,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into4.into4; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -59,18 +59,16 @@ public Choice5 diverge() { * {@inheritDoc} */ @Override - public Choice3 converge(Function> convergenceFn) { - return match(Choice3::a, - Choice3::b, - Choice3::c, - convergenceFn.andThen(cp3 -> cp3.match(Choice3::a, Choice3::b, Choice3::c))); + public Choice3 converge(Fn1> convergenceFn) { + return match(Choice3::a, Choice3::b, Choice3::c, + convergenceFn.fmap(cp3 -> cp3.match(Choice3::a, Choice3::b, Choice3::c))); } /** * {@inheritDoc} */ @Override - public final Choice4 fmap(Function fn) { + public final Choice4 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -78,23 +76,21 @@ public final Choice4 fmap(Function fn) { * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public final Choice4 biMapL(Function fn) { - return (Choice4) Bifunctor.super.biMapL(fn); + public final Choice4 biMapL(Fn1 fn) { + return (Choice4) Bifunctor.super.biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public final Choice4 biMapR(Function fn) { - return (Choice4) Bifunctor.super.biMapR(fn); + public final Choice4 biMapR(Fn1 fn) { + return (Choice4) Bifunctor.super.biMapR(fn); } @Override - public final Choice4 biMap(Function lFn, - Function rFn) { + public final Choice4 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice4::a, Choice4::b, c -> c(lFn.apply(c)), d -> d(rFn.apply(d))); } @@ -110,7 +106,7 @@ public Choice4 pure(E e) { * {@inheritDoc} */ @Override - public Choice4 zip(Applicative, Choice4> appFn) { + public Choice4 zip(Applicative, Choice4> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -119,7 +115,7 @@ public Choice4 zip(Applicative, */ @Override public Lazy> lazyZip( - Lazy, Choice4>> lazyAppFn) { + Lazy, Choice4>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), @@ -146,7 +142,7 @@ public Choice4 discardR(Applicative> appB * {@inheritDoc} */ @Override - public Choice4 flatMap(Function>> f) { + public Choice4 flatMap(Fn1>> f) { return match(Choice4::a, Choice4::b, Choice4::c, d -> f.apply(d).coerce()); } @@ -157,8 +153,8 @@ public Choice4 flatMap(Function, TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice4.a(a)).coerce(), b -> pure.apply((TravB) Choice4.b(b)).coerce(), c -> pure.apply((TravB) Choice4.c(c)), @@ -230,8 +226,8 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return aFn.apply(a); } @@ -263,8 +259,8 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return bFn.apply(b); } @@ -296,8 +292,8 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return cFn.apply(c); } @@ -329,8 +325,8 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return dFn.apply(d); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index 4008fde0b..e3e4a7958 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct5; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple5; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -12,7 +13,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into5.into5; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -59,19 +59,16 @@ public Choice6 diverge() { * {@inheritDoc} */ @Override - public Choice4 converge(Function> convergenceFn) { - return match(Choice4::a, - Choice4::b, - Choice4::c, - Choice4::d, - convergenceFn.andThen(cp4 -> cp4.match(Choice4::a, Choice4::b, Choice4::c, Choice4::d))); + public Choice4 converge(Fn1> convergenceFn) { + return match(Choice4::a, Choice4::b, Choice4::c, Choice4::d, + convergenceFn.fmap(cp4 -> cp4.match(Choice4::a, Choice4::b, Choice4::c, Choice4::d))); } /** * {@inheritDoc} */ @Override - public Choice5 fmap(Function fn) { + public Choice5 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -79,26 +76,24 @@ public Choice5 fmap(Function fn) { * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public Choice5 biMapL(Function fn) { - return (Choice5) Bifunctor.super.biMapL(fn); + public Choice5 biMapL(Fn1 fn) { + return (Choice5) Bifunctor.super.biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public Choice5 biMapR(Function fn) { - return (Choice5) Bifunctor.super.biMapR(fn); + public Choice5 biMapR(Fn1 fn) { + return (Choice5) Bifunctor.super.biMapR(fn); } /** * {@inheritDoc} */ @Override - public Choice5 biMap(Function lFn, - Function rFn) { + public Choice5 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice5::a, Choice5::b, Choice5::c, d -> d(lFn.apply(d)), e -> e(rFn.apply(e))); } @@ -114,7 +109,7 @@ public Choice5 pure(F f) { * {@inheritDoc} */ @Override - public Choice5 zip(Applicative, Choice5> appFn) { + public Choice5 zip(Applicative, Choice5> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -123,7 +118,7 @@ public Choice5 zip(Applicative Lazy> lazyZip( - Lazy, Choice5>> lazyAppFn) { + Lazy, Choice5>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), @@ -151,7 +146,7 @@ public Choice5 discardR(Applicative * {@inheritDoc} */ @Override - public Choice5 flatMap(Function>> f) { + public Choice5 flatMap(Fn1>> f) { return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, e -> f.apply(e).coerce()); } @@ -162,8 +157,8 @@ public Choice5 flatMap(Function, TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice5.a(a)).coerce(), b -> pure.apply((TravB) Choice5.b(b)).coerce(), c -> pure.apply((TravB) Choice5.c(c)), @@ -256,9 +251,9 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return aFn.apply(a); } @@ -290,9 +285,9 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return bFn.apply(b); } @@ -324,9 +319,9 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return cFn.apply(c); } @@ -358,9 +353,9 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return dFn.apply(d); } @@ -392,9 +387,9 @@ private _E(E e) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return eFn.apply(e); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index 0f09db9fa..dd788fb5b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct6; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple6; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -12,7 +13,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into6.into6; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -60,20 +60,16 @@ public Choice7 diverge() { * {@inheritDoc} */ @Override - public Choice5 converge(Function> convergenceFn) { - return match(Choice5::a, - Choice5::b, - Choice5::c, - Choice5::d, - Choice5::e, - convergenceFn.andThen(cp5 -> cp5.match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, Choice5::e))); + public Choice5 converge(Fn1> convergenceFn) { + return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, Choice5::e, + convergenceFn.fmap(cp5 -> cp5.match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, Choice5::e))); } /** * {@inheritDoc} */ @Override - public Choice6 fmap(Function fn) { + public Choice6 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -82,7 +78,7 @@ public Choice6 fmap(Function fn) { */ @Override @SuppressWarnings("unchecked") - public Choice6 biMapL(Function fn) { + public Choice6 biMapL(Fn1 fn) { return (Choice6) Bifunctor.super.biMapL(fn); } @@ -91,7 +87,7 @@ public Choice6 biMapL(Function fn) */ @Override @SuppressWarnings("unchecked") - public Choice6 biMapR(Function fn) { + public Choice6 biMapR(Fn1 fn) { return (Choice6) Bifunctor.super.biMapR(fn); } @@ -99,8 +95,8 @@ public Choice6 biMapR(Function fn) * {@inheritDoc} */ @Override - public Choice6 biMap(Function lFn, - Function rFn) { + public Choice6 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, e -> e(lFn.apply(e)), f -> f(rFn.apply(f))); } @@ -117,7 +113,7 @@ public Choice6 pure(G g) { */ @Override public Choice6 zip( - Applicative, Choice6> appFn) { + Applicative, Choice6> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -126,7 +122,7 @@ public Choice6 zip( */ @Override public Lazy> lazyZip( - Lazy, Choice6>> lazyAppFn) { + Lazy, Choice6>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), @@ -155,8 +151,7 @@ public Choice6 discardR(Applicative Choice6 flatMap( - Function>> fn) { + public Choice6 flatMap(Fn1>> fn) { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, f -> fn.apply(f).coerce()); } @@ -167,8 +162,8 @@ public Choice6 flatMap( @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice6.a(a)).coerce(), b -> pure.apply((TravB) Choice6.b(b)).coerce(), c -> pure.apply((TravB) Choice6.c(c)), @@ -283,9 +278,9 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return aFn.apply(a); } @@ -315,9 +310,9 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return bFn.apply(b); } @@ -347,9 +342,9 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return cFn.apply(c); } @@ -379,9 +374,9 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return dFn.apply(d); } @@ -411,9 +406,9 @@ private _E(E e) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return eFn.apply(e); } @@ -443,9 +438,9 @@ private _F(F f) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return fFn.apply(f); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index 6965a2d37..a72489ecb 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct7; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple7; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -12,7 +13,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into7.into7; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -61,22 +61,17 @@ public Choice8 diverge() { * {@inheritDoc} */ @Override - public Choice6 converge( - Function> convergenceFn) { - return match(Choice6::a, - Choice6::b, - Choice6::c, - Choice6::d, - Choice6::e, - Choice6::f, - convergenceFn.andThen(cp6 -> cp6.match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, Choice6::f))); + public Choice6 converge(Fn1> convergenceFn) { + return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, Choice6::f, + convergenceFn.fmap(cp6 -> cp6.match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, + Choice6::f))); } /** * {@inheritDoc} */ @Override - public Choice7 fmap(Function fn) { + public Choice7 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -84,26 +79,24 @@ public Choice7 fmap(Function fn * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public Choice7 biMapL(Function fn) { - return (Choice7) Bifunctor.super.biMapL(fn); + public Choice7 biMapL(Fn1 fn) { + return (Choice7) Bifunctor.super.biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public Choice7 biMapR(Function fn) { - return (Choice7) Bifunctor.super.biMapR(fn); + public Choice7 biMapR(Fn1 fn) { + return (Choice7) Bifunctor.super.biMapR(fn); } /** * {@inheritDoc} */ @Override - public Choice7 biMap(Function lFn, - Function rFn) { + public Choice7 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, f -> f(lFn.apply(f)), g -> g(rFn.apply(g))); } @@ -120,7 +113,7 @@ public Choice7 pure(H h) { */ @Override public Choice7 zip( - Applicative, Choice7> appFn) { + Applicative, Choice7> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -129,7 +122,7 @@ public Choice7 zip( */ @Override public Lazy> lazyZip( - Lazy, Choice7>> lazyAppFn) { + Lazy, Choice7>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), @@ -160,7 +153,7 @@ public Choice7 discardR(Applicative Choice7 flatMap( - Function>> fn) { + Fn1>> fn) { return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, g -> fn.apply(g).coerce()); } @@ -171,8 +164,8 @@ public Choice7 flatMap( @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice7.a(a)).coerce(), b -> pure.apply((TravB) Choice7.b(b)).coerce(), c -> pure.apply((TravB) Choice7.c(c)), @@ -311,10 +304,10 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return aFn.apply(a); } @@ -344,10 +337,10 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return bFn.apply(b); } @@ -377,10 +370,10 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return cFn.apply(c); } @@ -410,10 +403,10 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return dFn.apply(d); } @@ -443,10 +436,10 @@ private _E(E e) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return eFn.apply(e); } @@ -476,10 +469,10 @@ private _F(F f) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return fFn.apply(f); } @@ -509,10 +502,10 @@ private _G(G g) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return gFn.apply(g); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index a55590886..2d21f27ba 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct8; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple8; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -12,7 +13,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into8.into8; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -54,22 +54,17 @@ public Tuple8, Maybe, Maybe, Maybe, Maybe, Maybe, Maybe< */ @Override public Choice7 converge( - Function> convergenceFn) { - return match(Choice7::a, - Choice7::b, - Choice7::c, - Choice7::d, - Choice7::e, - Choice7::f, - Choice7::g, - convergenceFn.andThen(cp7 -> cp7.match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g))); + Fn1> convergenceFn) { + return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g, + convergenceFn.fmap(cp7 -> cp7.match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, + Choice7::f, Choice7::g))); } /** * {@inheritDoc} */ @Override - public Choice8 fmap(Function fn) { + public Choice8 fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -77,26 +72,24 @@ public Choice8 fmap(Function * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public Choice8 biMapL(Function fn) { - return (Choice8) Bifunctor.super.biMapL(fn); + public Choice8 biMapL(Fn1 fn) { + return (Choice8) Bifunctor.super.biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public Choice8 biMapR(Function fn) { - return (Choice8) Bifunctor.super.biMapR(fn); + public Choice8 biMapR(Fn1 fn) { + return (Choice8) Bifunctor.super.biMapR(fn); } /** * {@inheritDoc} */ @Override - public Choice8 biMap(Function lFn, - Function rFn) { + public Choice8 biMap(Fn1 lFn, + Fn1 rFn) { return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, g -> g(lFn.apply(g)), h -> h(rFn.apply(h))); } @@ -113,7 +106,7 @@ public Choice8 pure(I i) { */ @Override public Choice8 zip( - Applicative, Choice8> appFn) { + Applicative, Choice8> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -122,7 +115,7 @@ public Choice8 zip( */ @Override public Lazy> lazyZip( - Lazy, Choice8>> lazyAppFn) { + Lazy, Choice8>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazy(b(b)), c -> lazy(c(c)), @@ -154,7 +147,7 @@ public Choice8 discardR(Applicative Choice8 flatMap( - Function>> fn) { + Fn1>> fn) { return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, Choice8::g, h -> fn.apply(h).coerce()); } @@ -165,8 +158,8 @@ public Choice8 flatMap( @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(a -> pure.apply((TravB) Choice8.a(a)).coerce(), b -> pure.apply((TravB) Choice8.b(b)).coerce(), c -> pure.apply((TravB) Choice8.c(c)), @@ -332,10 +325,10 @@ private _A(A a) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return aFn.apply(a); } @@ -365,10 +358,10 @@ private _B(B b) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return bFn.apply(b); } @@ -398,10 +391,10 @@ private _C(C c) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return cFn.apply(c); } @@ -431,10 +424,10 @@ private _D(D d) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return dFn.apply(d); } @@ -464,10 +457,10 @@ private _E(E e) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return eFn.apply(e); } @@ -497,10 +490,10 @@ private _F(F f) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return fFn.apply(f); } @@ -530,10 +523,10 @@ private _G(G g) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return gFn.apply(g); } @@ -563,10 +556,10 @@ private _H(H h) { } @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return hFn.apply(h); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java index 5ad1a9908..ecb08fece 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2.java @@ -6,8 +6,6 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - 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; @@ -32,12 +30,12 @@ public interface CoProduct2> { /** * Type-safe convergence requiring a match against all potential types. * + * @param result type * @param aFn morphism A -> R * @param bFn morphism B -> R - * @param result type * @return the result of applying the appropriate morphism to this coproduct's unwrapped value */ - R match(Function aFn, Function bFn); + R match(Fn1 aFn, Fn1 bFn); /** * Diverge this coproduct by introducing another possible type that it could represent. As no morphisms can be @@ -63,8 +61,8 @@ public interface CoProduct2> { default CoProduct3> diverge() { return new CoProduct3>() { @Override - public R match(Function aFn, Function bFn, - Function cFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return CoProduct2.this.match(aFn, bFn); } }; @@ -107,7 +105,7 @@ default Maybe projectB() { default CoProduct2> invert() { return new CoProduct2>() { @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return CoProduct2.this.match(bFn, aFn); } }; @@ -118,14 +116,13 @@ public R match(Function aFn, Function result type * @param aFn morphism A v B -> R, applied in the A case * @param bFn morphism A v B -> R, applied in the B case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn) { + default R embed(Fn1 aFn, Fn1 bFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn))) .apply((CP2) this); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java index 23a97ac9c..aee747317 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3.java @@ -1,11 +1,10 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.product.Product3; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - 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; @@ -27,15 +26,14 @@ public interface CoProduct3> { /** * Type-safe convergence requiring a match against all potential types. * + * @param result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R - * @param result type * @return the result of applying the appropriate morphism to this coproduct's unwrapped value - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, Function bFn, - Function cFn); + R match(Fn1 aFn, Fn1 bFn, Fn1 cFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -47,8 +45,8 @@ R match(Function aFn, Function CoProduct4> diverge() { return new CoProduct4>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn) { return CoProduct3.this.match(aFn, bFn, cFn); } }; @@ -68,18 +66,8 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { - return match(a -> new CoProduct2>() { - @Override - public R match(Function aFn, Function bFn) { - return aFn.apply(a); - } - }, b -> new CoProduct2>() { - @Override - public R match(Function aFn, Function bFn) { - return bFn.apply(b); - } - }, convergenceFn); + Fn1> convergenceFn) { + return match(Choice2::a, Choice2::b, convergenceFn::apply); } /** @@ -126,16 +114,15 @@ default Maybe projectC() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct3#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C -> R, applied in the A case * @param bFn morphism A v B v C -> R, applied in the B case * @param cFn morphism A v B v C -> R, applied in the C case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn) { + default R embed(Fn1 aFn, Fn1 bFn, + Fn1 cFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn))) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java index 2ec2e113d..c8466dfa1 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.lambda.adt.product.Product4; import com.jnape.palatable.lambda.functions.Fn1; @@ -28,18 +29,18 @@ public interface CoProduct4> { /** * Type-safe convergence requiring a match against all potential types. * + * @param result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R * @param dFn morphism D -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -51,9 +52,9 @@ R match(Function aFn, default CoProduct5> diverge() { return new CoProduct5>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn) { return CoProduct4.this.match(aFn, bFn, cFn, dFn); } }; @@ -68,26 +69,8 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { - return match(a -> new CoProduct3>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn) { - return aFn.apply(a); - } - }, b -> new CoProduct3>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn) { - return bFn.apply(b); - } - }, c -> new CoProduct3>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn) { - return cFn.apply(c); - } - }, convergenceFn); + Fn1> convergenceFn) { + return match(Choice3::a, Choice3::b, Choice3::c, convergenceFn::apply); } /** @@ -144,18 +127,18 @@ default Maybe projectD() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct4#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D -> R, applied in the A case * @param bFn morphism A v B v C v D -> R, applied in the B case * @param cFn morphism A v B v C v D -> R, applied in the C case * @param dFn morphism A v B v C v D -> R, applied in the D case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java index b90aab2f5..03b594ca2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5.java @@ -1,11 +1,10 @@ package com.jnape.palatable.lambda.adt.coproduct; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.choice.Choice4; import com.jnape.palatable.lambda.adt.product.Product5; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - 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; @@ -29,20 +28,20 @@ public interface CoProduct5 result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R * @param dFn morphism D -> R * @param eFn morphism E -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -54,9 +53,9 @@ R match(Function aFn, default CoProduct6> diverge() { return new CoProduct6>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn) { return CoProduct5.this.match(aFn, bFn, cFn, dFn, eFn); } }; @@ -70,32 +69,8 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { - return match(a -> new CoProduct4>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { - return aFn.apply(a); - } - }, b -> new CoProduct4>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { - return bFn.apply(b); - } - }, c -> new CoProduct4>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { - return cFn.apply(c); - } - }, d -> new CoProduct4>() { - @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn) { - return dFn.apply(d); - } - }, convergenceFn::apply); + Fn1> convergenceFn) { + return match(Choice4::a, Choice4::b, Choice4::c, Choice4::d, convergenceFn::apply); } /** @@ -162,20 +137,20 @@ default Maybe projectE() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct5#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D v E -> R, applied in the A case * @param bFn morphism A v B v C v D v E -> R, applied in the B case * @param cFn morphism A v B v C v D v E -> R, applied in the C case * @param dFn morphism A v B v C v D v E -> R, applied in the D case * @param eFn morphism A v B v C v D v E -> R, applied in the E case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java index a3aa40163..084b3860d 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java @@ -31,22 +31,22 @@ public interface CoProduct6 result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R * @param dFn morphism D -> R * @param eFn morphism E -> R * @param fFn morphism F -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -58,10 +58,10 @@ R match(Function aFn, default CoProduct7> diverge() { return new CoProduct7>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn) { return CoProduct6.this.match(aFn, bFn, cFn, dFn, eFn, fFn); } }; @@ -75,7 +75,7 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { + Fn1> convergenceFn) { return match(Choice5::a, Choice5::b, Choice5::c, Choice5::d, Choice5::e, convergenceFn::apply); } @@ -153,22 +153,22 @@ default Maybe projectF() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct6#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D v E v F -> R, applied in the A case * @param bFn morphism A v B v C v D v E v F -> R, applied in the B case * @param cFn morphism A v B v C v D v E v F -> R, applied in the C case * @param dFn morphism A v B v C v D v E v F -> R, applied in the D case * @param eFn morphism A v B v C v D v E v F -> R, applied in the E case * @param fFn morphism A v B v C v D v E v F -> R, applied in the F case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java index 18086211c..0f7647f96 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7.java @@ -5,8 +5,6 @@ import com.jnape.palatable.lambda.adt.product.Product7; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - 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; @@ -32,6 +30,7 @@ public interface CoProduct7 result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R @@ -39,17 +38,16 @@ public interface CoProduct7E -> R * @param fFn morphism F -> R * @param gFn morphism G -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn, - Function gFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn, + Fn1 gFn); /** * Diverge this coproduct by introducing another possible type that it could represent. @@ -61,10 +59,10 @@ R match(Function aFn, default CoProduct8> diverge() { return new CoProduct8>() { @Override - public R match(Function aFn, Function bFn, - Function cFn, Function dFn, - Function eFn, Function fFn, - Function gFn, Function hFn) { + public R match(Fn1 aFn, Fn1 bFn, + Fn1 cFn, Fn1 dFn, + Fn1 eFn, Fn1 fFn, + Fn1 gFn, Fn1 hFn) { return CoProduct7.this.match(aFn, bFn, cFn, dFn, eFn, fFn, gFn); } }; @@ -78,7 +76,7 @@ public R match(Function aFn, Function> converge( - Function> convergenceFn) { + Fn1> convergenceFn) { return match(Choice6::a, Choice6::b, Choice6::c, Choice6::d, Choice6::e, Choice6::f, convergenceFn::apply); } @@ -166,6 +164,7 @@ default Maybe projectG() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct7#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D v E v F v G -> R, applied in the A case * @param bFn morphism A v B v C v D v E v F v G -> R, applied in the B case * @param cFn morphism A v B v C v D v E v F v G -> R, applied in the C case @@ -173,17 +172,16 @@ default Maybe projectG() { * @param eFn morphism A v B v C v D v E v F v G -> R, applied in the E case * @param fFn morphism A v B v C v D v E v F v G -> R, applied in the F case * @param gFn morphism A v B v C v D v E v F v G -> R, applied in the G case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn, - Function gFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn, + Fn1 gFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java index 776f067e8..9653e178a 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8.java @@ -5,8 +5,6 @@ import com.jnape.palatable.lambda.adt.product.Product8; import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - 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; @@ -33,6 +31,7 @@ public interface CoProduct8 result type * @param aFn morphism A -> R * @param bFn morphism B -> R * @param cFn morphism C -> R @@ -41,18 +40,17 @@ public interface CoProduct8F -> R * @param gFn morphism G -> R * @param hFn morphism H -> R - * @param result type * @return the result of applying the appropriate morphism from whichever type is represented by this coproduct to R - * @see CoProduct2#match(Function, Function) + * @see CoProduct2#match(Fn1, Fn1) */ - R match(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn, - Function gFn, - Function hFn); + R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn, + Fn1 gFn, + Fn1 hFn); /** * Converge this coproduct down to a lower order coproduct by mapping the last possible type into an earlier @@ -62,8 +60,9 @@ R match(Function aFn, * @return a {@link CoProduct7}<A, B, C, D, E, F, G> */ default CoProduct7> converge( - Function> convergenceFn) { - return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g, convergenceFn::apply); + Fn1> convergenceFn) { + return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, Choice7::g, + convergenceFn::apply); } /** @@ -160,6 +159,7 @@ default Maybe projectH() { * the appropriate morphism to this coproduct as a whole. Like {@link CoProduct8#match}, but without unwrapping the * value. * + * @param result type * @param aFn morphism A v B v C v D v E v F v G v H -> R, applied in the A case * @param bFn morphism A v B v C v D v E v F v G v H -> R, applied in the B case * @param cFn morphism A v B v C v D v E v F v G v H -> R, applied in the C case @@ -168,18 +168,17 @@ default Maybe projectH() { * @param fFn morphism A v B v C v D v E v F v G v H -> R, applied in the F case * @param gFn morphism A v B v C v D v E v F v G v H -> R, applied in the G case * @param hFn morphism A v B v C v D v E v F v G v H -> R, applied in the H case - * @param result type * @return the result of applying the appropriate morphism to this coproduct */ @SuppressWarnings("unchecked") - default R embed(Function aFn, - Function bFn, - Function cFn, - Function dFn, - Function eFn, - Function fFn, - Function gFn, - Function hFn) { + default R embed(Fn1 aFn, + Fn1 bFn, + Fn1 cFn, + Fn1 dFn, + Fn1 eFn, + Fn1 fFn, + Fn1 gFn, + Fn1 hFn) { return this.>match(constantly(fn1(aFn)), constantly(fn1(bFn)), constantly(fn1(cFn)), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index 44bff3484..ca8f76b5c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -2,13 +2,12 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.hlist.HList.HNil; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - /** * A singleton HList. Supports random access. * @@ -33,7 +32,7 @@ public <_0> Tuple2<_0, _1> cons(_0 _0) { } @Override - public <_1Prime> SingletonHList<_1Prime> fmap(Function fn) { + public <_1Prime> SingletonHList<_1Prime> fmap(Fn1 fn) { return Monad.super.<_1Prime>fmap(fn).coerce(); } @@ -44,13 +43,13 @@ public <_1Prime> SingletonHList<_1Prime> pure(_1Prime _1Prime) { @Override public <_1Prime> SingletonHList<_1Prime> zip( - Applicative, SingletonHList> appFn) { + Applicative, SingletonHList> appFn) { return Monad.super.zip(appFn).coerce(); } @Override public <_1Prime> Lazy> lazyZip( - Lazy, SingletonHList>> lazyAppFn) { + Lazy, SingletonHList>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_1Prime, SingletonHList>::coerce); } @@ -65,17 +64,15 @@ public <_1Prime> SingletonHList<_1> discardR(Applicative<_1Prime, SingletonHList } @Override - public <_1Prime> SingletonHList<_1Prime> flatMap( - Function>> f) { + public <_1Prime> SingletonHList<_1Prime> flatMap(Fn1>> f) { return f.apply(head()).coerce(); } @Override - @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return fn.apply(head()).fmap(SingletonHList::new).fmap(Applicative::coerce).coerce(); } @@ -86,7 +83,7 @@ AppTrav extends Applicative> AppTrav traverse(Function the return type of the function * @return the result of applying the head to the function */ - public R into(Function fn) { + public R into(Fn1 fn) { return 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 9f952849b..afb1d9e95 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 @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -9,7 +10,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Map; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -77,25 +77,25 @@ public Tuple2<_2, _1> invert() { } @Override - public <_2Prime> Tuple2<_1, _2Prime> fmap(Function fn) { + public <_2Prime> Tuple2<_1, _2Prime> fmap(Fn1 fn) { return Monad.super.<_2Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_1Prime> Tuple2<_1Prime, _2> biMapL(Function fn) { + public <_1Prime> Tuple2<_1Prime, _2> biMapL(Fn1 fn) { return (Tuple2<_1Prime, _2>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_2Prime> Tuple2<_1, _2Prime> biMapR(Function fn) { + public <_2Prime> Tuple2<_1, _2Prime> biMapR(Fn1 fn) { return (Tuple2<_1, _2Prime>) Bifunctor.super.biMapR(fn); } @Override - public <_1Prime, _2Prime> Tuple2<_1Prime, _2Prime> biMap(Function lFn, - Function rFn) { + public <_1Prime, _2Prime> Tuple2<_1Prime, _2Prime> biMap(Fn1 lFn, + Fn1 rFn) { return new Tuple2<>(lFn.apply(_1()), tail().fmap(rFn)); } @@ -106,13 +106,13 @@ public <_2Prime> Tuple2<_1, _2Prime> pure(_2Prime _2Prime) { @Override public <_2Prime> Tuple2<_1, _2Prime> zip( - Applicative, Tuple2<_1, ?>> appFn) { + Applicative, Tuple2<_1, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } @Override public <_2Prime> Lazy> lazyZip( - Lazy, Tuple2<_1, ?>>> lazyAppFn) { + Lazy, Tuple2<_1, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_2Prime, Tuple2<_1, ?>>::coerce); } @@ -127,16 +127,15 @@ public <_2Prime> Tuple2<_1, _2> discardR(Applicative<_2Prime, Tuple2<_1, ?>> app } @Override - public <_2Prime> Tuple2<_1, _2Prime> flatMap(Function>> f) { + public <_2Prime> Tuple2<_1, _2Prime> flatMap(Fn1>> f) { return pure(f.apply(_2).>coerce()._2()); } @Override - @SuppressWarnings("unchecked") public <_2Prime, App extends Applicative, TravB extends Traversable<_2Prime, Tuple2<_1, ?>>, AppB extends Applicative<_2Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return fn.apply(_2).fmap(_2Prime -> fmap(constantly(_2Prime))).fmap(Applicative::coerce).coerce(); } 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 dd57f1771..74f21bc8f 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 @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product3; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -79,25 +80,25 @@ public Tuple3<_2, _1, _3> invert() { @Override @SuppressWarnings("unchecked") - public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Function fn) { + public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Fn1 fn) { return (Tuple3<_1, _2, _3Prime>) Monad.super.fmap(fn); } @Override @SuppressWarnings("unchecked") - public <_2Prime> Tuple3<_1, _2Prime, _3> biMapL(Function fn) { + public <_2Prime> Tuple3<_1, _2Prime, _3> biMapL(Fn1 fn) { return (Tuple3<_1, _2Prime, _3>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_3Prime> Tuple3<_1, _2, _3Prime> biMapR(Function fn) { + public <_3Prime> Tuple3<_1, _2, _3Prime> biMapR(Fn1 fn) { return (Tuple3<_1, _2, _3Prime>) Bifunctor.super.biMapR(fn); } @Override - public <_2Prime, _3Prime> Tuple3<_1, _2Prime, _3Prime> biMap(Function lFn, - Function rFn) { + public <_2Prime, _3Prime> Tuple3<_1, _2Prime, _3Prime> biMap(Fn1 lFn, + Fn1 rFn) { return new Tuple3<>(_1(), tail().biMap(lFn, rFn)); } @@ -108,13 +109,13 @@ public <_3Prime> Tuple3<_1, _2, _3Prime> pure(_3Prime _3Prime) { @Override public <_3Prime> Tuple3<_1, _2, _3Prime> zip( - Applicative, Tuple3<_1, _2, ?>> appFn) { - return biMapR(appFn.>>coerce()._3()); + Applicative, Tuple3<_1, _2, ?>> appFn) { + return biMapR(appFn.>>coerce()._3()::apply); } @Override public <_3Prime> Lazy> lazyZip( - Lazy, Tuple3<_1, _2, ?>>> lazyAppFn) { + Lazy, Tuple3<_1, _2, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_3Prime, Tuple3<_1, _2, ?>>::coerce); } @@ -130,16 +131,15 @@ public <_3Prime> Tuple3<_1, _2, _3> discardR(Applicative<_3Prime, Tuple3<_1, _2, @Override public <_3Prime> Tuple3<_1, _2, _3Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_3).>coerce()._3); } @Override - @SuppressWarnings("unchecked") public <_3Prime, App extends Applicative, TravB extends Traversable<_3Prime, Tuple3<_1, _2, ?>>, AppB extends Applicative<_3Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return fn.apply(_3).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } 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 7ffeb72c5..90a1d3ec6 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 @@ -2,14 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product4; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -96,23 +95,23 @@ public Tuple4<_2, _1, _3, _4> invert() { } @Override - public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(Function fn) { + public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(Fn1 fn) { return (Tuple4<_1, _2, _3, _4Prime>) Monad.super.<_4Prime>fmap(fn); } @Override - public <_3Prime> Tuple4<_1, _2, _3Prime, _4> biMapL(Function fn) { + public <_3Prime> Tuple4<_1, _2, _3Prime, _4> biMapL(Fn1 fn) { return (Tuple4<_1, _2, _3Prime, _4>) Bifunctor.super.<_3Prime>biMapL(fn); } @Override - public <_4Prime> Tuple4<_1, _2, _3, _4Prime> biMapR(Function fn) { + public <_4Prime> Tuple4<_1, _2, _3, _4Prime> biMapR(Fn1 fn) { return (Tuple4<_1, _2, _3, _4Prime>) Bifunctor.super.<_4Prime>biMapR(fn); } @Override - public <_3Prime, _4Prime> Tuple4<_1, _2, _3Prime, _4Prime> biMap(Function lFn, - Function rFn) { + public <_3Prime, _4Prime> Tuple4<_1, _2, _3Prime, _4Prime> biMap(Fn1 lFn, + Fn1 rFn) { return new Tuple4<>(_1(), tail().biMap(lFn, rFn)); } @@ -123,13 +122,13 @@ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> pure(_4Prime _4Prime) { @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> zip( - Applicative, Tuple4<_1, _2, _3, ?>> appFn) { - return biMapR(appFn.>>coerce()._4()); + Applicative, Tuple4<_1, _2, _3, ?>> appFn) { + return biMapR(appFn.>>coerce()._4()::apply); } @Override public <_4Prime> Lazy> lazyZip( - Lazy, Tuple4<_1, _2, _3, ?>>> lazyAppFn) { + Lazy, Tuple4<_1, _2, _3, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_4Prime, Tuple4<_1, _2, _3, ?>>::coerce); } @@ -145,16 +144,15 @@ public <_4Prime> Tuple4<_1, _2, _3, _4> discardR(Applicative<_4Prime, Tuple4<_1, @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_4).>coerce()._4); } @Override - @SuppressWarnings("unchecked") public <_4Prime, App extends Applicative, TravB extends Traversable<_4Prime, Tuple4<_1, _2, _3, ?>>, AppB extends Applicative<_4Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return fn.apply(_4).fmap(_4Prime -> fmap(constantly(_4Prime))).fmap(Applicative::coerce).coerce(); } 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 7e6eeb24f..2e321fbae 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 @@ -2,14 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product5; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -114,25 +113,25 @@ public Tuple5<_2, _1, _3, _4, _5> invert() { } @Override - public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Function fn) { + public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Fn1 fn) { return Monad.super.<_5Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_4Prime> Tuple5<_1, _2, _3, _4Prime, _5> biMapL(Function fn) { + public <_4Prime> Tuple5<_1, _2, _3, _4Prime, _5> biMapL(Fn1 fn) { return (Tuple5<_1, _2, _3, _4Prime, _5>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> biMapR(Function fn) { + public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> biMapR(Fn1 fn) { return (Tuple5<_1, _2, _3, _4, _5Prime>) Bifunctor.super.biMapR(fn); } @Override - public <_4Prime, _5Prime> Tuple5<_1, _2, _3, _4Prime, _5Prime> biMap(Function lFn, - Function rFn) { + public <_4Prime, _5Prime> Tuple5<_1, _2, _3, _4Prime, _5Prime> biMap(Fn1 lFn, + Fn1 rFn) { return new Tuple5<>(_1(), tail().biMap(lFn, rFn)); } @@ -143,13 +142,13 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> pure(_5Prime _5Prime) { @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> zip( - Applicative, Tuple5<_1, _2, _3, _4, ?>> appFn) { + Applicative, Tuple5<_1, _2, _3, _4, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } @Override public <_5Prime> Lazy> lazyZip( - Lazy, Tuple5<_1, _2, _3, _4, ?>>> lazyAppFn) { + Lazy, Tuple5<_1, _2, _3, _4, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_5Prime, Tuple5<_1, _2, _3, _4, ?>>::coerce); } @@ -165,16 +164,15 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5> discardR(Applicative<_5Prime, Tuple5 @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_5).>coerce()._5()); } @Override - @SuppressWarnings("unchecked") public <_5Prime, App extends Applicative, TravB extends Traversable<_5Prime, Tuple5<_1, _2, _3, _4, ?>>, AppB extends Applicative<_5Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return fn.apply(_5).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 464a5abcd..4ec22546b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -2,14 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product6; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -133,26 +132,26 @@ public Tuple6<_2, _1, _3, _4, _5, _6> invert() { } @Override - public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> fmap(Function fn) { + public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> fmap(Fn1 fn) { return Monad.super.<_6Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_5Prime> Tuple6<_1, _2, _3, _4, _5Prime, _6> biMapL(Function fn) { + public <_5Prime> Tuple6<_1, _2, _3, _4, _5Prime, _6> biMapL(Fn1 fn) { return (Tuple6<_1, _2, _3, _4, _5Prime, _6>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> biMapR(Function fn) { + public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> biMapR(Fn1 fn) { return (Tuple6<_1, _2, _3, _4, _5, _6Prime>) Bifunctor.super.biMapR(fn); } @Override public <_5Prime, _6Prime> Tuple6<_1, _2, _3, _4, _5Prime, _6Prime> biMap( - Function lFn, - Function rFn) { + Fn1 lFn, + Fn1 rFn) { return new Tuple6<>(_1(), tail().biMap(lFn, rFn)); } @@ -163,13 +162,13 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> pure(_6Prime _6Prime) { @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> zip( - Applicative, Tuple6<_1, _2, _3, _4, _5, ?>> appFn) { + Applicative, Tuple6<_1, _2, _3, _4, _5, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } @Override public <_6Prime> Lazy> lazyZip( - Lazy, Tuple6<_1, _2, _3, _4, _5, ?>>> lazyAppFn) { + Lazy, Tuple6<_1, _2, _3, _4, _5, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>::coerce); } @@ -186,16 +185,15 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6> discardR(Applicative<_6Prime, Tu @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_6).>coerce()._6()); } @Override - @SuppressWarnings("unchecked") public <_6Prime, App extends Applicative, TravB extends Traversable<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>, AppB extends Applicative<_6Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return fn.apply(_6).fmap(_6Prime -> fmap(constantly(_6Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index bd0c6bbf4..e42cc4968 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -2,14 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product7; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -152,26 +151,26 @@ public Tuple7<_2, _1, _3, _4, _5, _6, _7> invert() { } @Override - public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> fmap(Function fn) { + public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> fmap(Fn1 fn) { return Monad.super.<_7Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_6Prime> Tuple7<_1, _2, _3, _4, _5, _6Prime, _7> biMapL(Function fn) { + public <_6Prime> Tuple7<_1, _2, _3, _4, _5, _6Prime, _7> biMapL(Fn1 fn) { return (Tuple7<_1, _2, _3, _4, _5, _6Prime, _7>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> biMapR(Function fn) { + public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> biMapR(Fn1 fn) { return (Tuple7<_1, _2, _3, _4, _5, _6, _7Prime>) Bifunctor.super.biMapR(fn); } @Override public <_6Prime, _7Prime> Tuple7<_1, _2, _3, _4, _5, _6Prime, _7Prime> biMap( - Function lFn, - Function rFn) { + Fn1 lFn, + Fn1 rFn) { return new Tuple7<>(_1(), tail().biMap(lFn, rFn)); } @@ -182,13 +181,13 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> pure(_7Prime _7Prime) { @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> zip( - Applicative, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appFn) { + Applicative, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } @Override public <_7Prime> Lazy> lazyZip( - Lazy, Tuple7<_1, _2, _3, _4, _5, _6, ?>>> lazyAppFn) { + Lazy, Tuple7<_1, _2, _3, _4, _5, _6, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>::coerce); } @@ -206,17 +205,16 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7> discardR( @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_7).>coerce()._7()); } @Override - @SuppressWarnings("unchecked") public <_7Prime, App extends Applicative, TravB extends Traversable<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, AppB extends Applicative<_7Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return fn.apply(_7).fmap(_7Prime -> fmap(constantly(_7Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index b30e68a76..e9db4aba9 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -2,14 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product8; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -171,26 +170,26 @@ public Tuple8<_2, _1, _3, _4, _5, _6, _7, _8> invert() { } @Override - public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> fmap(Function fn) { + public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> fmap(Fn1 fn) { return Monad.super.<_8Prime>fmap(fn).coerce(); } @Override @SuppressWarnings("unchecked") - public <_7Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8> biMapL(Function fn) { + public <_7Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8> biMapL(Fn1 fn) { return (Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8>) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> biMapR(Function fn) { + public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> biMapR(Fn1 fn) { return (Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime>) Bifunctor.super.biMapR(fn); } @Override public <_7Prime, _8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8Prime> biMap( - Function lFn, - Function rFn) { + Fn1 lFn, + Fn1 rFn) { return new Tuple8<>(_1(), tail().biMap(lFn, rFn)); } @@ -201,13 +200,13 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> pure(_8Prime _8Prim @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> zip( - Applicative, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appFn) { + Applicative, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } @Override public <_8Prime> Lazy> lazyZip( - Lazy, + Lazy, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>::coerce); } @@ -226,17 +225,16 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> discardR( @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> flatMap( - Function>> f) { + Fn1>> f) { return pure(f.apply(_8).>coerce()._8()); } @Override - @SuppressWarnings("unchecked") public <_8Prime, App extends Applicative, TravB extends Traversable<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, AppB extends Applicative<_8Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return fn.apply(_8).fmap(_8Prime -> fmap(constantly(_8Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java index 4c3d64da0..0a76df761 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product2.java @@ -1,9 +1,9 @@ package com.jnape.palatable.lambda.adt.product; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn2; import java.util.Map; -import java.util.function.BiFunction; /** * The minimal shape of the combination of two potentially distinctly typed values, supporting destructuring via @@ -35,11 +35,11 @@ public interface Product2<_1, _2> extends Map.Entry<_1, _2> { * Destructure and apply this product to a function accepting the same number of arguments as this product's * slots. This can be thought of as a kind of dual to uncurrying a function and applying a product to it. * - * @param fn the function to apply * @param the return type of the function + * @param fn the function to apply * @return the result of applying the destructured product to the function */ - default R into(BiFunction fn) { + default R into(Fn2 fn) { return fn.apply(_1(), _2()); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java index 063456453..18da0491f 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product3.java @@ -30,7 +30,7 @@ public interface Product3<_1, _2, _3> extends Product2<_1, _2> { * @return the result of applying the destructured product to the function */ default R into(Fn3 fn) { - return Product2.super.into(fn.toBiFunction()).apply(_3()); + return Product2.super.into(fn).apply(_3()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java b/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java index 2703f8229..87a33376d 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/product/Product4.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.adt.product; import com.jnape.palatable.lambda.adt.hlist.Tuple4; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn4; /** @@ -31,7 +32,7 @@ public interface Product4<_1, _2, _3, _4> extends Product3<_1, _2, _3> { * @return the result of applying the destructured product to the function */ default R into(Fn4 fn) { - return Product3.super.into(fn).apply(_4()); + return Product3.super.>into(fn).apply(_4()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 3115bef10..8516c19c8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -1,13 +1,14 @@ package com.jnape.palatable.lambda.functions; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.io.IO; import java.util.function.Consumer; -import java.util.function.Function; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.io.IO.io; @@ -16,76 +17,77 @@ * * @param the argument type * @see Fn0 - * @see Consumer */ @FunctionalInterface -public interface Effect extends Fn1>, Consumer { +public interface Effect extends Fn1> { - void checkedAccept(A a) throws Throwable; + @Override + IO checkedApply(A a) throws Throwable; + + /** + * Convert this {@link Effect} to a java {@link Consumer} + * + * @return the {@link Consumer} + */ + default Consumer toConsumer() { + return a -> apply(a).unsafePerformIO(); + } + /** + * {@inheritDoc} + */ @Override - default void accept(A a) { + default IO apply(A a) { try { - checkedAccept(a); + return checkedApply(a); } catch (Throwable t) { throw Runtime.throwChecked(t); } } + /** + * {@inheritDoc} + */ @Override - default IO apply(A a) { - return io(() -> accept(a)); - } - - @Override - default IO checkedApply(A a) throws Throwable { - return io(() -> accept(a)); - } - - @Override - default Effect diMapL(Function fn) { + default Effect diMapL(Fn1 fn) { return effect(Fn1.super.diMapL(fn)); } + /** + * {@inheritDoc} + */ @Override - default Effect contraMap(Function fn) { + default Effect contraMap(Fn1 fn) { return effect(Fn1.super.contraMap(fn)); } - @Override - default Effect compose(Function before) { - return effect(Fn1.super.compose(before)); - } - + /** + * {@inheritDoc} + */ @Override default Effect discardR(Applicative> appB) { return effect(Fn1.super.discardR(appB)); } - @Override - default Effect andThen(Consumer after) { - return Consumer.super.andThen(after)::accept; - } - /** - * Static factory method to aid in inference. + * Static factory method to create an {@link Effect} from a java {@link Consumer}. * - * @param effect the effect - * @param the effect argument type - * @return the effect + * @param consumer the {@link Consumer} + * @param the input type + * @return the {@link Effect} */ - static Effect effect(Consumer effect) { - return effect::accept; + static Effect fromConsumer(Consumer consumer) { + return a -> io(() -> consumer.accept(a)); } /** - * Create an {@link Effect} from a {@link Runnable}; + * Create an {@link Effect} from a {@link SideEffect}; * - * @param runnable the runnable - * @return the effect + * @param sideEffect the {@link SideEffect} + * @return the {@link Effect} */ - static Effect effect(Runnable runnable) { - return effect(constantly(io(runnable))); + static Effect effect(SideEffect sideEffect) { + return effect(constantly(io(sideEffect))); } /** @@ -96,6 +98,6 @@ static Effect effect(Runnable runnable) { * @return the effect */ static Effect effect(Fn1> fn) { - return a -> fn.apply(a).unsafePerformIO(); + return fn.fmap(io -> io.fmap(constantly(UNIT)))::apply; } } \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index 902bcd940..3352046fe 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -5,7 +5,6 @@ import com.jnape.palatable.lambda.monad.Monad; import java.util.concurrent.Callable; -import java.util.function.Function; import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Unit.UNIT; @@ -15,11 +14,10 @@ * * @param the result type * @see Fn1 - * @see Supplier * @see Callable */ @FunctionalInterface -public interface Fn0 extends Fn1, Supplier, Callable { +public interface Fn0 extends Fn1 { A checkedApply() throws Throwable; @@ -32,6 +30,24 @@ default A apply() { return apply(UNIT); } + /** + * Convert this {@link Fn0} to a java {@link Supplier} + * + * @return the {@link Supplier} + */ + default Supplier toSupplier() { + return this::apply; + } + + /** + * Convert this {@link Fn0} to a java {@link Callable} + * + * @return the {@link Callable} + */ + default Callable toCallable() { + return this::apply; + } + /** * {@inheritDoc} */ @@ -41,12 +57,12 @@ default A checkedApply(Unit unit) throws Throwable { } @Override - default Fn0 flatMap(Function>> f) { + default Fn0 flatMap(Fn1>> f) { return Fn1.super.flatMap(f).thunk(UNIT); } @Override - default Fn0 fmap(Function f) { + default Fn0 fmap(Fn1 f) { return Fn1.super.fmap(f).thunk(UNIT); } @@ -56,7 +72,7 @@ default Fn0 pure(B b) { } @Override - default Fn0 zip(Applicative, Fn1> appFn) { + default Fn0 zip(Applicative, Fn1> appFn) { return Fn1.super.zip(appFn).thunk(UNIT); } @@ -76,30 +92,10 @@ default Fn0 discardR(Applicative> appB) { } @Override - default Fn0 diMapR(Function fn) { + default Fn0 diMapR(Fn1 fn) { return Fn1.super.diMapR(fn).thunk(UNIT); } - @Override - default Fn1 compose(Function before) { - return Fn1.super.compose(before)::apply; - } - - @Override - default Fn0 andThen(Function after) { - return Fn1.super.andThen(after).thunk(UNIT); - } - - @Override - default A get() { - return apply(); - } - - @Override - default A call() { - return apply(); - } - /** * Convenience method for converting a {@link Supplier} to an {@link Fn0}. * @@ -107,42 +103,41 @@ default A call() { * @param the output type * @return the {@link Fn0} */ - static Fn0 fn0(Supplier supplier) { + static Fn0 fromSupplier(Supplier supplier) { return supplier::get; } /** - * Static factory method for coercing a lambda to an {@link Fn0}. + * Convenience method for converting a {@link Callable} to an {@link Fn0}. * - * @param fn the lambda to coerce - * @param the output type + * @param callable the callable + * @param the output type * @return the {@link Fn0} */ - static Fn0 fn0(Fn0 fn) { - return fn; + static Fn0 fromCallable(Callable callable) { + return callable::call; } /** - * Static factory method for adapting a {@link Runnable} to an {@link Fn0}<{@link Unit}>. + * Static factory method for coercing a lambda to an {@link Fn0}. * - * @param runnable the {@link Runnable} + * @param fn the lambda to coerce + * @param the output type * @return the {@link Fn0} */ - static Fn0 fn0(Runnable runnable) { - return fn0(() -> { - runnable.run(); - return UNIT; - }); + static Fn0 fn0(Fn0 fn) { + return fn; } /** - * Static factory method for adapting a {@link Function} to an {@link Fn0}. + * Static factory method for adapting an {@link Fn1}<Unit, A> to an + * {@link Fn0}<A>. * - * @param fn the {@link Function} + * @param fn the {@link Fn1} * @param the output type * @return the {@link Fn0} */ - static Fn0 fn0(Function fn) { + static Fn0 fn0(Fn1 fn) { return fn0(() -> fn.apply(UNIT)); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 8704f92f4..49c69d2de 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -10,7 +10,6 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; -import java.util.function.BiFunction; import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn2.fn2; @@ -27,8 +26,7 @@ public interface Fn1 extends Monad>, Cartesian>, - Cocartesian>, - Function { + Cocartesian> { /** * Invoke this function explosively with the given argument. @@ -49,6 +47,7 @@ default B apply(A a) { * * @param a the argument * @return the result of the function application + * @throws Throwable anything possibly thrown by the function */ B checkedApply(A a) throws Throwable; @@ -73,11 +72,20 @@ default Fn2 widen() { return fn2(constantly(this)); } + /** + * Convert this {@link Fn1} to a java {@link Function}. + * + * @return the {@link Function} + */ + default Function toFunction() { + return this::apply; + } + /** * {@inheritDoc} */ @Override - default Fn1 flatMap(Function>> f) { + default Fn1 flatMap(Fn1>> f) { return a -> f.apply(apply(a)).>coerce().apply(a); } @@ -89,8 +97,8 @@ default Fn1 flatMap(Function>> * @return a function representing the composition of this function and f */ @Override - default Fn1 fmap(Function f) { - return Monad.super.fmap(f).coerce(); + default Fn1 fmap(Fn1 f) { + return a -> f.apply(apply(a)); } /** @@ -105,7 +113,7 @@ default Fn1 pure(C c) { * {@inheritDoc} */ @Override - default Fn1 zip(Applicative, Fn1> appFn) { + default Fn1 zip(Applicative, Fn1> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -114,15 +122,14 @@ default Fn1 zip(Applicative, Fn1 Fn1 zip(Fn2 appFn) { - return zip((Fn1>) (Object) appFn); + return zip((Fn1>) (Object) appFn); } /** * {@inheritDoc} */ @Override - default Lazy> lazyZip( - Lazy, Fn1>> lazyAppFn) { + default Lazy> lazyZip(Lazy, Fn1>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } @@ -151,7 +158,7 @@ default Fn1 discardR(Applicative> appB) { * @return an {@link Fn1}<Z, B> */ @Override - default Fn1 diMapL(Function fn) { + default Fn1 diMapL(Fn1 fn) { return (Fn1) Cartesian.super.diMapL(fn); } @@ -164,7 +171,7 @@ default Fn1 diMapL(Function fn) { * @return an {@link Fn1}<A, C> */ @Override - default Fn1 diMapR(Function fn) { + default Fn1 diMapR(Fn1 fn) { return (Fn1) Cartesian.super.diMapR(fn); } @@ -178,8 +185,8 @@ default Fn1 diMapR(Function fn) { * @return an {@link Fn1}<Z, C> */ @Override - default Fn1 diMap(Function lFn, Function rFn) { - return lFn.andThen(this).andThen(rFn)::apply; + default Fn1 diMap(Fn1 lFn, Fn1 rFn) { + return lFn.fmap(this).fmap(rFn)::apply; } /** @@ -222,36 +229,12 @@ default Fn1> choose() { return a -> Either.trying(() -> apply(a), constantly(a)).match(Choice2::a, Choice2::b); } - @Override - default Fn1 contraMap(Function fn) { - return (Fn1) Cartesian.super.contraMap(fn); - } - /** - * Override of {@link Function#compose(Function)}, returning an instance of {@link Fn1} for compatibility. - * Right-to-left composition. - * - * @param before the function who's return value is this function's argument - * @param the new argument type - * @return an {@link Fn1}<Z, B> + * {@inheritDoc} */ @Override - default Fn1 compose(Function before) { - return z -> apply(before.apply(z)); - } - - /** - * Right-to-left composition between different arity functions. Preserves highest arity in the return type, - * specialized to lambda types (in this case, {@link BiFunction} -> {@link Fn2}). - * - * @param before the function to pass its return value to this function's input - * @param the resulting function's first argument type - * @param the resulting function's second argument type - * @return an {@link Fn2}<Y, Z, B> - */ - @SuppressWarnings({"overloads"}) - default Fn2 compose(BiFunction before) { - return compose(fn2(before)); + default Fn1 contraMap(Fn1 fn) { + return (Fn1) Cartesian.super.contraMap(fn); } /** @@ -262,47 +245,43 @@ default Fn2 compose(BiFunction the resulting function's second argument type * @return an {@link Fn2}<Y, Z, B> */ - @SuppressWarnings({"overloads"}) default Fn2 compose(Fn2 before) { - return fn2(before.fmap(this::compose))::apply; + return fn2(before.fmap(this::contraMap))::apply; } /** - * Left-to-right composition between different arity functions. Preserves highest arity in the return type, - * specialized to lambda types (in this case, {@link BiFunction} -> {@link Fn2}). + * Left-to-right composition between different arity functions. Preserves highest arity in the return type. * * @param after the function to invoke on this function's return value * @param the resulting function's second argument type * @param the resulting function's return type * @return an {@link Fn2}<A, C, D> */ - default Fn2 andThen(BiFunction after) { + default Fn2 andThen(Fn2 after) { return (a, c) -> after.apply(apply(a), c); } /** - * Override of {@link Function#andThen(Function)}, returning an instance of {@link Fn1} for compatibility. - * Left-to-right composition. + * Static factory method for avoid explicit casting when using method references as {@link Fn1}s. * - * @param after the function to invoke on this function's return value - * @param the new result type - * @return an {@link Fn1}<A, C> + * @param fn the function to adapt + * @param the input type + * @param the output type + * @return the {@link Fn1} */ - @Override - default Fn1 andThen(Function after) { - return a -> after.apply(apply(a)); + static Fn1 fn1(Fn1 fn) { + return fn::apply; } /** - * Static factory method for wrapping a {@link Function} in an {@link Fn1}. Useful for avoid explicit casting when - * using method references as {@link Fn1}s. + * Static factory method for wrapping a java {@link Function} in an {@link Fn1}. * - * @param function the function to adapt - * @param the input argument type + * @param function the function + * @param the input type * @param the output type * @return the {@link Fn1} */ - static Fn1 fn1(Function function) { + static Fn1 fromFunction(Function function) { return function::apply; } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index cbe3a0929..7620ea9a7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -57,18 +57,6 @@ default Fn3 widen() { return fn3(constantly(this)); } - /** - * Same as normal composition, except that the result is an instance of {@link Fn2} for convenience. - * - * @param before the function who's return value is this function's argument - * @param the new argument type - * @return an {@link Fn2}<Z, B, C> - */ - @Override - default Fn2 compose(Function before) { - return fn2(Fn1.super.compose(before)); - } - /** * Partially apply this function by passing its first argument. * @@ -120,7 +108,7 @@ default Fn2 discardR(Applicative> appB) { * {@inheritDoc} */ @Override - default Fn2 diMapL(Function fn) { + default Fn2 diMapL(Fn1 fn) { return fn2(Fn1.super.diMapL(fn)); } @@ -128,18 +116,10 @@ default Fn2 diMapL(Function fn) { * {@inheritDoc} */ @Override - default Fn2 contraMap(Function fn) { + default Fn2 contraMap(Fn1 fn) { return fn2(Fn1.super.contraMap(fn)); } - /** - * {@inheritDoc} - */ - @Override - default Fn3 compose(BiFunction before) { - return fn3(Fn1.super.compose(before)); - } - /** * {@inheritDoc} */ @@ -149,8 +129,7 @@ default Fn3 compose(Fn2 be } /** - * Static factory method for wrapping a {@link BiFunction} in an {@link Fn2}. Useful for avoid explicit casting when - * using method references as {@link Fn2}s. + * Static factory method for wrapping a {@link BiFunction} in an {@link Fn2}. * * @param biFunction the biFunction to adapt * @param the first input argument type @@ -158,7 +137,7 @@ default Fn3 compose(Fn2 be * @param the output type * @return the {@link Fn2} */ - static Fn2 fn2(BiFunction biFunction) { + static Fn2 fromBiFunction(BiFunction biFunction) { return biFunction::apply; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java index 84b46a1ae..9003aa0ac 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java @@ -4,9 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; -import java.util.function.BiFunction; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.Fn4.fn4; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -106,20 +103,15 @@ default Fn3 discardR(Applicative> appB) { } @Override - default Fn3 diMapL(Function fn) { + default Fn3 diMapL(Fn1 fn) { return fn3(Fn2.super.diMapL(fn)); } @Override - default Fn3 contraMap(Function fn) { + default Fn3 contraMap(Fn1 fn) { return fn3(Fn2.super.contraMap(fn)); } - @Override - default Fn4 compose(BiFunction before) { - return fn4(Fn2.super.compose(before)); - } - @Override default Fn4 compose(Fn2 before) { return fn4(Fn2.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java index e38856550..aa49270d5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java @@ -4,9 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; -import java.util.function.BiFunction; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.Fn5.fn5; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -121,20 +118,15 @@ default Fn4 discardR(Applicative> appB) { } @Override - default Fn4 diMapL(Function fn) { + default Fn4 diMapL(Fn1 fn) { return fn4(Fn3.super.diMapL(fn)); } @Override - default Fn4 contraMap(Function fn) { + default Fn4 contraMap(Fn1 fn) { return fn4(Fn3.super.contraMap(fn)); } - @Override - default Fn5 compose(BiFunction before) { - return fn5(Fn3.super.compose(before)); - } - @Override default Fn5 compose(Fn2 before) { return fn5(Fn3.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java index 16bc6efa2..b0c0acfba 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java @@ -4,9 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; -import java.util.function.BiFunction; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.Fn6.fn6; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -138,20 +135,15 @@ default Fn5 discardR(Applicative> appB) { } @Override - default Fn5 diMapL(Function fn) { + default Fn5 diMapL(Fn1 fn) { return fn5(Fn4.super.diMapL(fn)); } @Override - default Fn5 contraMap(Function fn) { + default Fn5 contraMap(Fn1 fn) { return fn5(Fn4.super.contraMap(fn)); } - @Override - default Fn6 compose(BiFunction before) { - return fn6(Fn4.super.compose(before)); - } - @Override default Fn6 compose(Fn2 before) { return fn6(Fn4.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java index 62917ce3a..0f06798c6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java @@ -4,9 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; -import java.util.function.BiFunction; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.Fn7.fn7; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -155,20 +152,15 @@ default Fn6 discardR(Applicative> appB) { } @Override - default Fn6 diMapL(Function fn) { + default Fn6 diMapL(Fn1 fn) { return fn6(Fn5.super.diMapL(fn)); } @Override - default Fn6 contraMap(Function fn) { + default Fn6 contraMap(Fn1 fn) { return fn6(Fn5.super.contraMap(fn)); } - @Override - default Fn7 compose(BiFunction before) { - return fn7(Fn5.super.compose(before)); - } - @Override default Fn7 compose(Fn2 before) { return fn7(Fn5.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index 2e18bef97..70b7ba3f6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -4,9 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; -import java.util.function.BiFunction; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.Fn8.fn8; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -172,20 +169,15 @@ default Fn7 discardR(Applicative> appB) } @Override - default Fn7 diMapL(Function fn) { + default Fn7 diMapL(Fn1 fn) { return fn7(Fn6.super.diMapL(fn)); } @Override - default Fn7 contraMap(Function fn) { + default Fn7 contraMap(Fn1 fn) { return fn7(Fn6.super.contraMap(fn)); } - @Override - default Fn8 compose(BiFunction before) { - return fn8(Fn6.super.compose(before)); - } - @Override default Fn8 compose(Fn2 before) { return fn8(Fn6.super.compose(before)); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java index 07e8fb165..040fa4346 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java @@ -4,9 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; import com.jnape.palatable.lambda.functor.Applicative; -import java.util.function.BiFunction; -import java.util.function.Function; - /** * A function taking six arguments. Defined in terms of {@link Fn7}, so similarly auto-curried. * @@ -180,21 +177,15 @@ default Fn8 discardR(Applicative> ap } @Override - default Fn8 diMapL(Function fn) { + default Fn8 diMapL(Fn1 fn) { return fn8(Fn7.super.diMapL(fn)); } @Override - default Fn8 contraMap(Function fn) { + default Fn8 contraMap(Fn1 fn) { return fn8(Fn7.super.contraMap(fn)); } - @Override - default Fn8> compose( - BiFunction before) { - return Fn7.super.compose(before); - } - @Override default Fn8> compose(Fn2 before) { return Fn7.super.compose(before); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java index dca2ebe09..6ea6e6254 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Empty.java @@ -25,6 +25,6 @@ public static Empty empty() { } public static Boolean empty(Iterable as) { - return Empty.empty().test(as); + return Empty.empty().apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java index e2b33f928..846762200 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Inits.java @@ -26,7 +26,7 @@ private Inits() { @Override public Iterable> checkedApply(Iterable as) { - return scanLeft(Snoc.snoc().flip().toBiFunction(), Collections::emptyIterator, as); + return scanLeft(Snoc.snoc().flip(), Collections::emptyIterator, as); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java index b50429e51..ce2d2e2a3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Magnetize.java @@ -19,7 +19,7 @@ private Magnetize() { @Override public Iterable> checkedApply(Iterable as) { - return magnetizeBy(eq().toBiFunction(), as); + return magnetizeBy(eq(), as); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java index 74374b434..e148fadcb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Not.java @@ -1,23 +1,22 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import java.util.function.Function; - /** * Negate a predicate function. * * @param the input argument type */ -public final class Not implements BiPredicate, A> { +public final class Not implements BiPredicate, A> { private static final Not INSTANCE = new Not<>(); private Not() { } @Override - public Boolean checkedApply(Function pred, A a) { + public Boolean checkedApply(Fn1 pred, A a) { return !pred.apply(a); } @@ -26,11 +25,11 @@ public static Not not() { return (Not) INSTANCE; } - public static Predicate not(Function pred) { + public static Predicate not(Fn1 pred) { return Not.not().apply(pred); } - public static Boolean not(Function pred, A a) { + public static Boolean not(Fn1 pred, A a) { return not(pred).apply(a); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java index 42a97c86f..26d76101f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/All.java @@ -3,8 +3,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; -import java.util.function.Function; - /** * Eagerly apply a predicate to each element in an Iterable, returning true if every element * satisfies the predicate, and false otherwise. This method short-circuits on the first false @@ -13,7 +11,7 @@ * @param The input Iterable element type * @see Any */ -public final class All implements BiPredicate, Iterable> { +public final class All implements BiPredicate, Iterable> { private static final All INSTANCE = new All<>(); @@ -21,7 +19,7 @@ private All() { } @Override - public Boolean checkedApply(Function predicate, Iterable as) { + public Boolean checkedApply(Fn1 predicate, Iterable as) { for (A a : as) if (!predicate.apply(a)) return false; @@ -34,11 +32,11 @@ public static All all() { return (All) INSTANCE; } - public static Fn1, ? extends Boolean> all(Function predicate) { + public static Fn1, ? extends Boolean> all(Fn1 predicate) { return All.all().apply(predicate); } - public static Boolean all(Function predicate, Iterable as) { + public static Boolean all(Fn1 predicate, Iterable as) { return All.all(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java index 048b79cef..524b83159 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Any.java @@ -1,10 +1,9 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import java.util.function.Function; - /** * Eagerly apply a predicate to each element in an Iterable, returning true if any element * satisfies the predicate, and false otherwise. This method short-circuits on the first true @@ -13,7 +12,7 @@ * @param The input Iterable element type * @see All */ -public final class Any implements BiPredicate, Iterable> { +public final class Any implements BiPredicate, Iterable> { private static final Any INSTANCE = new Any<>(); @@ -21,7 +20,7 @@ private Any() { } @Override - public Boolean checkedApply(Function predicate, Iterable as) { + public Boolean checkedApply(Fn1 predicate, Iterable as) { for (A a : as) if (predicate.apply(a)) return true; @@ -34,11 +33,11 @@ public static Any any() { return (Any) INSTANCE; } - public static Predicate> any(Function predicate) { + public static Predicate> any(Fn1 predicate) { return Any.any().apply(predicate); } - public static Boolean any(Function predicate, Iterable as) { + public static Boolean any(Fn1 predicate, Iterable as) { return Any.any(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java index fcd964c7c..0d22f7216 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Both.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn3; -import java.util.function.Function; - /** * Given two functions f and g, produce a * {@link Fn1}<A, {@link Tuple2}<B, C>> (the dual application of both functions). @@ -14,7 +12,8 @@ * @param the first function return type * @param the second function return type */ -public final class Both implements Fn3, Function, A, Tuple2> { +public final class Both implements + Fn3, Fn1, A, Tuple2> { private static final Both INSTANCE = new Both<>(); @@ -22,10 +21,8 @@ private Both() { } @Override - public Tuple2 checkedApply(Function f, - Function g, - A a) { - return Tuple2.fill(a).biMap(f, g); + public Tuple2 checkedApply(Fn1 f, Fn1 g, A a) { + return Tuple2.fill(a).biMap(f::apply, g::apply); } @SuppressWarnings("unchecked") @@ -33,19 +30,15 @@ public static Both both() { return (Both) INSTANCE; } - public static Fn1, Fn1>> both( - Function f) { + public static Fn1, Fn1>> both(Fn1 f) { return Both.both().apply(f); } - public static Fn1> both(Function f, - Function g) { + public static Fn1> both(Fn1 f, Fn1 g) { return Both.both(f).apply(g); } - public static Tuple2 both(Function f, - Function g, - A a) { + public static Tuple2 both(Fn1 f, Fn1 g, A a) { return Both.both(f, g).apply(a); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java index 3585ef135..f91d8ba15 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.iteration.PredicatedDroppingIterable; -import java.util.function.Function; - /** * Lazily limit the Iterable by skipping the first contiguous group of elements that satisfy the predicate, * beginning iteration at the first element for which the predicate evaluates to false. @@ -16,7 +14,7 @@ * @see TakeWhile */ -public final class DropWhile implements Fn2, Iterable, Iterable> { +public final class DropWhile implements Fn2, Iterable, Iterable> { private static final DropWhile INSTANCE = new DropWhile<>(); @@ -24,7 +22,7 @@ private DropWhile() { } @Override - public Iterable checkedApply(Function predicate, Iterable as) { + public Iterable checkedApply(Fn1 predicate, Iterable as) { return new PredicatedDroppingIterable<>(predicate, as); } @@ -33,11 +31,11 @@ public static DropWhile dropWhile() { return (DropWhile) INSTANCE; } - public static Fn1, Iterable> dropWhile(Function predicate) { + public static Fn1, Iterable> dropWhile(Fn1 predicate) { return DropWhile.dropWhile().apply(predicate); } - public static Iterable dropWhile(Function predicate, Iterable as) { + public static Iterable dropWhile(Fn1 predicate, Iterable as) { return DropWhile.dropWhile(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java index f8954ae8e..2074ec59c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.iteration.FilteringIterable; -import java.util.function.Function; - /** * Lazily apply a predicate to each element in an Iterable, returning an Iterable of just the * elements for which the predicate evaluated to true. @@ -14,7 +12,7 @@ * @see TakeWhile * @see DropWhile */ -public final class Filter implements Fn2, Iterable, Iterable> { +public final class Filter implements Fn2, Iterable, Iterable> { private static final Filter INSTANCE = new Filter<>(); @@ -22,7 +20,7 @@ private Filter() { } @Override - public Iterable checkedApply(Function predicate, Iterable as) { + public Iterable checkedApply(Fn1 predicate, Iterable as) { return new FilteringIterable<>(predicate, as); } @@ -31,11 +29,11 @@ public static Filter filter() { return (Filter) INSTANCE; } - public static Fn1, Iterable> filter(Function predicate) { + public static Fn1, Iterable> filter(Fn1 predicate) { return Filter.filter().apply(predicate); } - public static Iterable filter(Function predicate, Iterable as) { + public static Iterable filter(Fn1 predicate, Iterable as) { return Filter.filter(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java index 5539d71fc..0bb5c4e6b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Find.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head; import static com.jnape.palatable.lambda.functions.builtin.fn1.Not.not; import static com.jnape.palatable.lambda.functions.builtin.fn2.DropWhile.dropWhile; @@ -18,7 +16,7 @@ * * @param the Iterable element type */ -public final class Find implements Fn2, Iterable, Maybe> { +public final class Find implements Fn2, Iterable, Maybe> { private static final Find INSTANCE = new Find<>(); @@ -26,7 +24,7 @@ private Find() { } @Override - public Maybe checkedApply(Function predicate, Iterable as) { + public Maybe checkedApply(Fn1 predicate, Iterable as) { return head(dropWhile(not(predicate), as)); } @@ -35,11 +33,11 @@ public static Find find() { return (Find) INSTANCE; } - public static Fn1, Maybe> find(Function predicate) { + public static Fn1, Maybe> find(Fn1 predicate) { return Find.find().apply(predicate); } - public static Maybe find(Function predicate, Iterable as) { + public static Maybe find(Fn1 predicate, Iterable as) { return Find.find(predicate).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java index 9cbc91ee8..42e61912a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupBy.java @@ -7,7 +7,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; @@ -20,7 +19,7 @@ * @param the Map value type * @see InGroupsOf */ -public final class GroupBy implements Fn2, Iterable, Map>> { +public final class GroupBy implements Fn2, Iterable, Map>> { private static final GroupBy INSTANCE = new GroupBy<>(); @@ -28,7 +27,7 @@ private GroupBy() { } @Override - public Map> checkedApply(Function keyFn, Iterable vs) { + public Map> checkedApply(Fn1 keyFn, Iterable vs) { return foldLeft((m, v) -> { m.computeIfAbsent(keyFn.apply(v), __ -> new ArrayList<>()).add(v); return m; @@ -40,11 +39,11 @@ public static GroupBy groupBy() { return (GroupBy) INSTANCE; } - public static Fn1, Map>> groupBy(Function keyFn) { + public static Fn1, Map>> groupBy(Fn1 keyFn) { return GroupBy.groupBy().apply(keyFn); } - public static Map> groupBy(Function keyFn, Iterable vs) { + public static Map> groupBy(Fn1 keyFn, Iterable vs) { return GroupBy.groupBy(keyFn).apply(vs); } } \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java index cd5b061de..523c08543 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into.java @@ -4,17 +4,16 @@ import com.jnape.palatable.lambda.functions.Fn2; import java.util.Map; -import java.util.function.BiFunction; /** - * Given a {@link BiFunction}<A, B, C> and a {@link Map.Entry}<A, B>, destructure - * the entry and apply the key and value as arguments to the function, returning the result. + * Given an {@link Fn2}<A, B, C> and a {@link Map.Entry}<A, B>, destructure the + * entry and apply the key and value as arguments to the function, returning the result. * * @param the first argument type * @param the second argument type * @param the result type */ -public final class Into implements Fn2, Map.Entry, C> { +public final class Into implements Fn2, Map.Entry, C> { private static final Into INSTANCE = new Into<>(); @@ -22,7 +21,7 @@ private Into() { } @Override - public C checkedApply(BiFunction fn, Map.Entry entry) { + public C checkedApply(Fn2 fn, Map.Entry entry) { return fn.apply(entry.getKey(), entry.getValue()); } @@ -32,11 +31,11 @@ public static Into into() { } public static Fn1, C> into( - BiFunction fn) { + Fn2 fn) { return Into.into().apply(fn); } - public static C into(BiFunction fn, + public static C into(Fn2 fn, Map.Entry entry) { return Into.into(fn).apply(entry); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java index 526fcb7e5..3b574146b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into1.java @@ -4,21 +4,19 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import java.util.function.Function; - /** - * Given a {@link Function}<A, B> and a {@link SingletonHList}<A>, - * pop the head and apply it to the function, returning the result. + * Given an {@link Fn1}<A, B> and a {@link SingletonHList}<A>, pop the head and + * apply it to the function, returning the result. * * @param the first argument type * @param the result type */ -public final class Into1 implements Fn2, SingletonHList, B> { +public final class Into1 implements Fn2, SingletonHList, B> { private static final Into1 INSTANCE = new Into1<>(); @Override - public B checkedApply(Function fn, SingletonHList singletonHList) { + public B checkedApply(Fn1 fn, SingletonHList singletonHList) { return fn.apply(singletonHList.head()); } @@ -27,11 +25,11 @@ public static Into1 into1() { return (Into1) INSTANCE; } - public static Fn1, B> into1(Function fn) { + public static Fn1, B> into1(Fn1 fn) { return Into1.into1().apply(fn); } - public static B into1(Function fn, SingletonHList singletonHList) { + public static B into1(Fn1 fn, SingletonHList singletonHList) { return Into1.into1(fn).apply(singletonHList); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java index 05daec1ef..d58969d57 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Into3.java @@ -20,7 +20,7 @@ public final class Into3 implements Fn2 fn, Product3 product) { - return product.into(fn); + return product.into(fn); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java index 17a96235c..19fba6f79 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Iterate.java @@ -3,20 +3,18 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn2.Unfoldr.unfoldr; /** - * Lazily generate an infinite Iterable from the successive applications of the function first to the - * initial seed value, then to the result, and so on; i.e., the result of iterate(x -> x + 1, 0) would - * produce an infinite Iterable over the elements 0, 1, 2, 3, ... and so on. + * Lazily generate an infinite {@link Iterable} from the successive applications of the function first to the initial + * seed value, then to the result, and so on; i.e., the result of iterate(x -> x + 1, 0) would produce + * an infinite {@link Iterable} over the elements 0, 1, 2, 3, ... and so on. * * @param The Iterable element type */ -public final class Iterate implements Fn2, A, Iterable> { +public final class Iterate implements Fn2, A, Iterable> { private static final Iterate INSTANCE = new Iterate<>(); @@ -24,7 +22,7 @@ private Iterate() { } @Override - public Iterable checkedApply(Function fn, A seed) { + public Iterable checkedApply(Fn1 fn, A seed) { return unfoldr(a -> just(tuple(a, fn.apply(a))), seed); } @@ -33,11 +31,11 @@ public static Iterate iterate() { return (Iterate) INSTANCE; } - public static Fn1> iterate(Function fn) { + public static Fn1> iterate(Fn1 fn) { return Iterate.iterate().apply(fn); } - public static Iterable iterate(Function fn, A seed) { + public static Iterable iterate(Fn1 fn, A seed) { return Iterate.iterate(fn).apply(seed); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java index fe14186b7..7ebb8fe6f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java @@ -4,16 +4,13 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functor.builtin.Lazy; -import java.util.function.BiFunction; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.monad.Monad.join; /** - * Given a {@link BiFunction} that receives a recursive function and an input and yields a {@link Lazy lazy} result, and - * an input, produce a {@link Lazy lazy} result that, when forced, will recursively invoke the function until it - * terminates in a stack-safe way. + * Given a {@link Fn2} that receives a recursive function and an input and yields a {@link Lazy lazy} result, and an + * input, produce a {@link Lazy lazy} result that, when forced, will recursively invoke the function until it terminates + * in a stack-safe way. *

* Example: *

@@ -29,8 +26,7 @@
  * @param  the input type
  * @param  the output type
  */
-public final class LazyRec implements
-        Fn2>, A, Lazy>, A, Lazy> {
+public final class LazyRec implements Fn2>, A, Lazy>, A, Lazy> {
 
     private static final LazyRec INSTANCE = new LazyRec<>();
 
@@ -38,7 +34,7 @@ private LazyRec() {
     }
 
     @Override
-    public Lazy checkedApply(BiFunction>, A, Lazy> fn, A a) {
+    public Lazy checkedApply(Fn2>, A, Lazy> fn, A a) {
         return join(lazy(() -> fn.apply(nextA -> apply(fn, nextA), a)));
     }
 
@@ -47,11 +43,11 @@ public static  LazyRec lazyRec() {
         return (LazyRec) INSTANCE;
     }
 
-    public static  Fn1> lazyRec(BiFunction>, A, Lazy> fn) {
+    public static  Fn1> lazyRec(Fn2>, A, Lazy> fn) {
         return LazyRec.lazyRec().apply(fn);
     }
 
-    public static  Lazy lazyRec(BiFunction>, A, Lazy> fn, A a) {
+    public static  Lazy lazyRec(Fn2>, A, Lazy> fn, A a) {
         return lazyRec(fn).apply(a);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java
index 6456f62fb..43697b8a5 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeBy.java
@@ -4,7 +4,6 @@
 import com.jnape.palatable.lambda.functions.Fn2;
 
 import java.util.Collections;
-import java.util.function.BiFunction;
 
 import static com.jnape.palatable.lambda.adt.Maybe.just;
 import static com.jnape.palatable.lambda.adt.Maybe.nothing;
@@ -25,7 +24,7 @@
  *
  * @param  the {@link Iterable} element type
  */
-public final class MagnetizeBy implements Fn2, Iterable, Iterable>> {
+public final class MagnetizeBy implements Fn2, Iterable, Iterable>> {
 
     private static final MagnetizeBy INSTANCE = new MagnetizeBy<>();
 
@@ -33,7 +32,7 @@ private MagnetizeBy() {
     }
 
     @Override
-    public Iterable> checkedApply(BiFunction predicate,
+    public Iterable> checkedApply(Fn2 predicate,
                                               Iterable as) {
         return () -> uncons(as).fmap(into((A head, Iterable tail) -> {
             Iterable group = cons(head, unfoldr(into((pivot, ys) -> uncons(ys)
@@ -50,12 +49,12 @@ public static  MagnetizeBy magnetizeBy() {
     }
 
     public static  Fn1, Iterable>> magnetizeBy(
-            BiFunction predicate) {
+            Fn2 predicate) {
         return MagnetizeBy.magnetizeBy().apply(predicate);
     }
 
     public static  Iterable> magnetizeBy(
-            BiFunction predicate,
+            Fn2 predicate,
             Iterable as) {
         return MagnetizeBy.magnetizeBy(predicate).apply(as);
     }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java
index 35c771ea1..f5f37332b 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java
@@ -4,8 +4,6 @@
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.iteration.MappingIterable;
 
-import java.util.function.Function;
-
 /**
  * Lazily apply a function to each element in an Iterable, producing an Iterable of the mapped
  * results.
@@ -13,7 +11,7 @@
  * @param  A type contravariant to the input Iterable element type
  * @param  A type covariant to the output Iterable element type
  */
-public final class Map implements Fn2, Iterable, Iterable> {
+public final class Map implements Fn2, Iterable, Iterable> {
 
     private static final Map INSTANCE = new Map<>();
 
@@ -21,7 +19,7 @@ private Map() {
     }
 
     @Override
-    public Iterable checkedApply(Function fn, Iterable as) {
+    public Iterable checkedApply(Fn1 fn, Iterable as) {
         return new MappingIterable<>(fn, as);
     }
 
@@ -30,11 +28,11 @@ public static  Map map() {
         return (Map) INSTANCE;
     }
 
-    public static  Fn1, Iterable> map(Function fn) {
+    public static  Fn1, Iterable> map(Fn1 fn) {
         return Map.map().apply(fn);
     }
 
-    public static  Iterable map(Function fn, Iterable as) {
+    public static  Iterable map(Fn1 fn, Iterable as) {
         return Map.map(fn).apply(as);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java
deleted file mode 100644
index 8adb7e847..000000000
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.jnape.palatable.lambda.functions.builtin.fn2;
-
-import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.functions.Fn2;
-
-import java.util.function.BiFunction;
-
-/**
- * Partially apply (fix) the first argument of a {@link BiFunction}, producing an Fn1 that
- * takes the remaining argument. This is isomorphic to calling {@link Fn2#apply(Object)}.
- *
- * @param  The type of the value to be supplied
- * @param  The input argument type of the resulting function
- * @param  The return type of the resulting function
- * @see Partial3
- */
-public final class Partial2 implements Fn2, A, Fn1> {
-
-    private static final Partial2 INSTANCE = new Partial2<>();
-
-    private Partial2() {
-    }
-
-    @Override
-    public Fn1 checkedApply(BiFunction fn, A a) {
-        return b -> fn.apply(a, b);
-    }
-
-    @SuppressWarnings("unchecked")
-    public static  Partial2, A, Fn1> partial2() {
-        return (Partial2, A, Fn1>) INSTANCE;
-    }
-
-    public static  Fn1> partial2(BiFunction fn) {
-        return Partial2.partial2().apply(new Partial2().toBiFunction(), fn);
-    }
-
-    public static  Fn1 partial2(BiFunction fn, A a) {
-        return partial2(fn).apply(a);
-    }
-}
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java
deleted file mode 100644
index 151d8f20f..000000000
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.jnape.palatable.lambda.functions.builtin.fn2;
-
-import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.functions.Fn3;
-
-/**
- * Partially apply (fix) the first argument of a Fn3, producing a Fn2 that takes the remaining
- * two argument. This is isomorphic to calling {@link Fn3#apply(Object)}.
- *
- * @param  The type of the value to be supplied
- * @param  The first input argument type of the resulting function
- * @param  The second input argument type of the resulting function
- * @param  The return type of the resulting function
- * @see Partial2
- */
-public final class Partial3 implements Fn2, A, Fn2> {
-
-    private static final Partial3 INSTANCE = new Partial3<>();
-
-    private Partial3() {
-    }
-
-    @Override
-    public Fn2 checkedApply(Fn3 fn, A a) {
-        return fn.apply(a);
-    }
-
-    @SuppressWarnings("unchecked")
-    public static  Partial3 partial3() {
-        return (Partial3) INSTANCE;
-    }
-
-    public static  Fn1> partial3(Fn3 fn) {
-        return Partial3.partial3().apply(fn);
-    }
-
-    public static  Fn2 partial3(Fn3 fn, A a) {
-        return partial3(fn).apply(a);
-    }
-}
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java
index 41acd66b9..20efa316f 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partition.java
@@ -6,7 +6,6 @@
 import com.jnape.palatable.lambda.functions.Fn2;
 
 import java.util.Collections;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map;
@@ -24,7 +23,7 @@
  * @param  The output right Iterable element type, as well as the CoProduct2 B type
  * @see CoProduct2
  */
-public final class Partition implements Fn2>, Iterable, Tuple2, Iterable>> {
+public final class Partition implements Fn2>, Iterable, Tuple2, Iterable>> {
 
     private static final Partition INSTANCE = new Partition<>();
 
@@ -32,7 +31,7 @@ private Partition() {
     }
 
     @Override
-    public Tuple2, Iterable> checkedApply(Function> function,
+    public Tuple2, Iterable> checkedApply(Fn1> function,
                                                          Iterable as) {
         return Tuple2.>>fill(map(function, as))
                 .biMap(Map., Iterable>map(cp -> cp.match(Collections::singleton, __ -> emptySet())),
@@ -46,12 +45,12 @@ public static  Partition partition() {
     }
 
     public static  Fn1, Tuple2, Iterable>> partition(
-            Function> function) {
+            Fn1> function) {
         return Partition.partition().apply(function);
     }
 
     public static  Tuple2, Iterable> partition(
-            Function> function,
+            Fn1> function,
             Iterable as) {
         return Partition.partition(function).apply(as);
     }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java
index c12c45d55..83a33484d 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java
@@ -1,20 +1,18 @@
 package com.jnape.palatable.lambda.functions.builtin.fn2;
 
+import com.jnape.palatable.lambda.functions.Effect;
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.functor.Functor;
 
-import java.util.function.Consumer;
-import java.util.function.Function;
-
 /**
- * Given a {@link Consumer}, "peek" at the value contained inside a {@link Functor} via
- * {@link Functor#fmap(Function)}, applying the {@link Consumer} to the contained value, if there is one.
+ * Given an {@link Effect}, "peek" at the value contained inside a {@link Functor} via {@link Functor#fmap(Fn1)},
+ * applying the {@link Effect} to the contained value, if there is one.
  *
  * @param   the functor parameter type
  * @param  the functor type
  */
-public final class Peek> implements Fn2, FA, FA> {
+public final class Peek> implements Fn2, FA, FA> {
     private static final Peek INSTANCE = new Peek<>();
 
     private Peek() {
@@ -22,9 +20,9 @@ private Peek() {
 
     @Override
     @SuppressWarnings("unchecked")
-    public FA checkedApply(Consumer consumer, FA fa) {
+    public FA checkedApply(Effect consumer, FA fa) {
         return (FA) fa.fmap(a -> {
-            consumer.accept(a);
+            consumer.apply(a).unsafePerformIO();
             return a;
         });
     }
@@ -34,11 +32,11 @@ public FA checkedApply(Consumer consumer, FA fa) {
         return (Peek) INSTANCE;
     }
 
-    public static > Fn1 peek(Consumer consumer) {
+    public static > Fn1 peek(Effect consumer) {
         return Peek.peek().apply(consumer);
     }
 
-    public static > FA peek(Consumer consumer, FA fa) {
+    public static > FA peek(Effect consumer, FA fa) {
         return Peek.peek(consumer).apply(fa);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java
index f9d63e0b6..7e3d3c465 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java
@@ -1,24 +1,22 @@
 package com.jnape.palatable.lambda.functions.builtin.fn2;
 
+import com.jnape.palatable.lambda.functions.Effect;
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.functor.Bifunctor;
 import com.jnape.palatable.lambda.functor.BoundedBifunctor;
 
-import java.util.function.Consumer;
-import java.util.function.Function;
-
 /**
- * Given two {@link Consumer}s, "peek" at the values contained inside a {@link Bifunctor} via
- * {@link Bifunctor#biMap(Function, Function)}, applying the {@link Consumer}s to the contained values,
- * if there are any.
+ * Given two {@link Effect}s, "peek" at the values contained inside a {@link Bifunctor} via
+ * {@link BoundedBifunctor#biMap(Fn1, Fn1)}, applying the {@link Effect}s to the contained values, if there are any.
  *
  * @param    the bifunctor's first parameter type
  * @param    the bifunctor's second parameter type
  * @param  the bifunctor type
  */
-public final class Peek2> implements Fn3, Consumer, FAB, FAB> {
+public final class Peek2> implements
+        Fn3, Effect, FAB, FAB> {
     private static final Peek2 INSTANCE = new Peek2<>();
 
     private Peek2() {
@@ -26,12 +24,12 @@ private Peek2() {
 
     @Override
     @SuppressWarnings("unchecked")
-    public FAB checkedApply(Consumer aConsumer, Consumer bConsumer, FAB fab) {
+    public FAB checkedApply(Effect aConsumer, Effect bConsumer, FAB fab) {
         return (FAB) fab.biMap(a -> {
-            aConsumer.accept(a);
+            aConsumer.apply(a).unsafePerformIO();
             return a;
         }, b -> {
-            bConsumer.accept(b);
+            bConsumer.apply(b).unsafePerformIO();
             return b;
         });
     }
@@ -41,20 +39,20 @@ public FAB checkedApply(Consumer aConsumer, Consumer bCons
         return (Peek2) INSTANCE;
     }
 
-    public static > Fn2, FAB, FAB> peek2(
-            Consumer aConsumer) {
+    public static > Fn2, FAB, FAB>
+    peek2(Effect aConsumer) {
         return Peek2.peek2().apply(aConsumer);
     }
 
     public static > Fn1 peek2(
-            Consumer aConsumer,
-            Consumer bConsumer) {
+            Effect aConsumer,
+            Effect bConsumer) {
         return Peek2.peek2(aConsumer).apply(bConsumer);
     }
 
     public static > FAB peek2(
-            Consumer aConsumer,
-            Consumer bConsumer,
+            Effect aConsumer,
+            Effect bConsumer,
             FAB fab) {
         return Peek2.peek2(aConsumer, bConsumer).apply(fab);
     }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java
index d77872e71..aae71023f 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceLeft.java
@@ -6,14 +6,13 @@
 import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft;
 
 import java.util.Iterator;
-import java.util.function.BiFunction;
 
 import static com.jnape.palatable.lambda.adt.Maybe.just;
 import static com.jnape.palatable.lambda.adt.Maybe.nothing;
 import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft;
 
 /**
- * Given an {@link Iterable}<A> and a {@link BiFunction}<A, A, A>, iteratively
+ * Given an {@link Iterable}<A> and a {@link Fn2}<A, A, A>, iteratively
  * accumulate over the {@link Iterable}, returning {@link Maybe}<A>. If the {@link Iterable} is
  * empty, the result is {@link Maybe#nothing()}; otherwise, the result is wrapped in {@link Maybe#just}. For this
  * reason, null accumulation results are considered erroneous and will throw.
@@ -25,7 +24,7 @@
  * @see ReduceRight
  * @see FoldLeft
  */
-public final class ReduceLeft implements Fn2, Iterable, Maybe> {
+public final class ReduceLeft implements Fn2, Iterable, Maybe> {
 
     private static final ReduceLeft INSTANCE = new ReduceLeft<>();
 
@@ -33,7 +32,7 @@ private ReduceLeft() {
     }
 
     @Override
-    public Maybe checkedApply(BiFunction fn, Iterable as) {
+    public Maybe checkedApply(Fn2 fn, Iterable as) {
         Iterator iterator = as.iterator();
         return !iterator.hasNext() ? nothing() : just(foldLeft(fn, iterator.next(), () -> iterator));
     }
@@ -43,11 +42,11 @@ public static  ReduceLeft reduceLeft() {
         return (ReduceLeft) INSTANCE;
     }
 
-    public static  Fn1, Maybe> reduceLeft(BiFunction fn) {
+    public static  Fn1, Maybe> reduceLeft(Fn2 fn) {
         return ReduceLeft.reduceLeft().apply(fn);
     }
 
-    public static  Maybe reduceLeft(BiFunction fn, Iterable as) {
+    public static  Maybe reduceLeft(Fn2 fn, Iterable as) {
         return ReduceLeft.reduceLeft(fn).apply(as);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java
index 97ed627d5..6d027c594 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ReduceRight.java
@@ -5,13 +5,11 @@
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight;
 
-import java.util.function.BiFunction;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Reverse.reverse;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft;
 
 /**
- * Given an {@link Iterable}<A> and a {@link BiFunction}<A, A, A>, iteratively
+ * Given an {@link Iterable}<A> and a {@link Fn2}<A, A, A>, iteratively
  * accumulate over the {@link Iterable}, returning {@link Maybe}<A>. If the {@link Iterable} is
  * empty, the result is {@link Maybe#nothing()}; otherwise, the result is wrapped in {@link Maybe#just}. For this
  * reason, null accumulation results are considered erroneous and will throw.
@@ -23,7 +21,7 @@
  * @see ReduceLeft
  * @see FoldRight
  */
-public final class ReduceRight implements Fn2, Iterable, Maybe> {
+public final class ReduceRight implements Fn2, Iterable, Maybe> {
 
     private static final ReduceRight INSTANCE = new ReduceRight<>();
 
@@ -31,7 +29,7 @@ private ReduceRight() {
     }
 
     @Override
-    public final Maybe checkedApply(BiFunction fn, Iterable as) {
+    public final Maybe checkedApply(Fn2 fn, Iterable as) {
         return reduceLeft((b, a) -> fn.apply(a, b), reverse(as));
     }
 
@@ -40,11 +38,11 @@ public static  ReduceRight reduceRight() {
         return (ReduceRight) INSTANCE;
     }
 
-    public static  Fn1, Maybe> reduceRight(BiFunction fn) {
+    public static  Fn1, Maybe> reduceRight(Fn2 fn) {
         return ReduceRight.reduceRight().apply(fn);
     }
 
-    public static  Maybe reduceRight(BiFunction fn, Iterable as) {
+    public static  Maybe reduceRight(Fn2 fn, Iterable as) {
         return ReduceRight.reduceRight(fn).apply(as);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java
index a00eaff48..2237966c3 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java
@@ -8,7 +8,6 @@
 import com.jnape.palatable.lambda.traversable.Traversable;
 
 import java.util.Map;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
 
@@ -34,7 +33,7 @@ public final class Sequence, Trav extends Tra
         AppA extends Applicative,
         TravA extends Traversable,
         AppTrav extends Applicative,
-        TravApp extends Traversable> implements Fn2, AppTrav> {
+        TravApp extends Traversable> implements Fn2, AppTrav> {
 
     private static final Sequence INSTANCE = new Sequence<>();
 
@@ -42,7 +41,7 @@ private Sequence() {
     }
 
     @Override
-    public AppTrav checkedApply(TravApp traversable, Function pure) {
+    public AppTrav checkedApply(TravApp traversable, Fn1 pure) {
         return traversable.traverse(id(), pure);
     }
 
@@ -59,7 +58,7 @@ TravApp extends Traversable> Sequence,
             TravA extends Traversable,
             AppTrav extends Applicative,
-            TravApp extends Traversable> Fn1, AppTrav> sequence(
+            TravApp extends Traversable> Fn1, AppTrav> sequence(
             TravApp traversable) {
         return Sequence.sequence().apply(traversable);
     }
@@ -69,33 +68,38 @@ TravApp extends Traversable> Sequence,
             AppTrav extends Applicative,
             TravApp extends Traversable> AppTrav sequence(TravApp traversable,
-                                                                      Function pure) {
+                                                                      Fn1 pure) {
         return Sequence.sequence(traversable).apply(pure);
     }
 
     @SuppressWarnings({"unchecked", "RedundantTypeArguments"})
-    public static , AppA extends Applicative, AppIterable extends Applicative, App>, IterableApp extends Iterable>
-    Fn1, ? extends AppIterable>, AppIterable> sequence(IterableApp iterableApp) {
+    public static , AppA extends Applicative,
+            AppIterable extends Applicative, App>,
+            IterableApp extends Iterable>
+    Fn1, ? extends AppIterable>, AppIterable> sequence(IterableApp iterableApp) {
         return pure -> (AppIterable) Sequence., LambdaIterable, AppA, Applicative, App>, LambdaIterable>sequence(
                 LambdaIterable.wrap(iterableApp), x -> pure.apply(x.unwrap()).fmap(LambdaIterable::wrap))
                 .fmap(LambdaIterable::unwrap);
     }
 
-    public static , AppA extends Applicative, AppIterable extends Applicative, App>, IterableApp extends Iterable>
-    AppIterable sequence(IterableApp iterableApp, Function, ? extends AppIterable> pure) {
+    public static , AppA extends Applicative,
+            AppIterable extends Applicative, App>, IterableApp extends Iterable>
+    AppIterable sequence(IterableApp iterableApp, Fn1, ? extends AppIterable> pure) {
         return Sequence.sequence(iterableApp).apply(pure);
     }
 
     @SuppressWarnings({"unchecked", "RedundantTypeArguments"})
-    public static , AppB extends Applicative, AppMap extends Applicative, App>, MapApp extends Map>
-    Fn1, ? extends AppMap>, AppMap> sequence(MapApp mapApp) {
+    public static , AppB extends Applicative,
+            AppMap extends Applicative, App>, MapApp extends Map>
+    Fn1, ? extends AppMap>, AppMap> sequence(MapApp mapApp) {
         return pure -> (AppMap) Sequence., LambdaMap, AppB, Applicative, App>, LambdaMap>sequence(
                 LambdaMap.wrap(mapApp), x -> pure.apply(x.unwrap()).fmap(LambdaMap::wrap))
                 .fmap(LambdaMap::unwrap);
     }
 
-    public static , AppB extends Applicative, AppMap extends Applicative, App>, MapApp extends Map>
-    AppMap sequence(MapApp mapApp, Function, ? extends AppMap> pure) {
+    public static , AppB extends Applicative,
+            AppMap extends Applicative, App>, MapApp extends Map>
+    AppMap sequence(MapApp mapApp, Fn1, ? extends AppMap> pure) {
         return Sequence.sequence(mapApp).apply(pure);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java
index de3d55858..13ea9d0df 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/SortBy.java
@@ -5,7 +5,6 @@
 import com.jnape.palatable.lambda.functions.builtin.fn1.Sort;
 
 import java.util.List;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.functions.builtin.fn2.SortWith.sortWith;
 import static java.util.Comparator.comparing;
@@ -20,7 +19,7 @@
  * @see Sort
  * @see SortWith
  */
-public final class SortBy> implements Fn2, Iterable, List> {
+public final class SortBy> implements Fn2, Iterable, List> {
 
     private static final SortBy INSTANCE = new SortBy<>();
 
@@ -28,8 +27,8 @@ private SortBy() {
     }
 
     @Override
-    public List checkedApply(Function fn, Iterable as) {
-        return sortWith(comparing(fn), as);
+    public List checkedApply(Fn1 fn, Iterable as) {
+        return sortWith(comparing(fn.toFunction()), as);
     }
 
     @SuppressWarnings("unchecked")
@@ -37,12 +36,11 @@ public static > SortBy sortBy() {
         return (SortBy) INSTANCE;
     }
 
-    public static > Fn1, List> sortBy(
-            Function fn) {
+    public static > Fn1, List> sortBy(Fn1 fn) {
         return SortBy.sortBy().apply(fn);
     }
 
-    public static > List sortBy(Function fn, Iterable as) {
+    public static > List sortBy(Fn1 fn, Iterable as) {
         return SortBy.sortBy(fn).apply(as);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java
index d74702b35..966b6518d 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Span.java
@@ -4,8 +4,6 @@
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn2.DropWhile.dropWhile;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.TakeWhile.takeWhile;
 
@@ -15,7 +13,8 @@
  *
  * @param  the {@link Iterable} element type
  */
-public final class Span implements Fn2, Iterable, Tuple2, Iterable>> {
+public final class Span implements
+        Fn2, Iterable, Tuple2, Iterable>> {
 
     private static final Span INSTANCE = new Span<>();
 
@@ -23,8 +22,7 @@ private Span() {
     }
 
     @Override
-    public Tuple2, Iterable> checkedApply(Function predicate,
-                                                         Iterable as) {
+    public Tuple2, Iterable> checkedApply(Fn1 predicate, Iterable as) {
         return Tuple2.fill(as).biMap(takeWhile(predicate), dropWhile(predicate));
     }
 
@@ -34,11 +32,11 @@ public static  Span span() {
     }
 
     public static  Fn1, Tuple2, Iterable>> span(
-            Function predicate) {
+            Fn1 predicate) {
         return Span.span().apply(predicate);
     }
 
-    public static  Tuple2, Iterable> span(Function predicate,
+    public static  Tuple2, Iterable> span(Fn1 predicate,
                                                             Iterable as) {
         return Span.span(predicate).apply(as);
     }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java
index 098cd6a17..d0d051dce 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java
@@ -4,8 +4,6 @@
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.iteration.PredicatedTakingIterable;
 
-import java.util.function.Function;
-
 /**
  * Lazily limit the Iterable to the first group of contiguous elements that satisfy the predicate by
  * iterating up to, but not including, the first element for which the predicate evaluates to false.
@@ -15,7 +13,7 @@
  * @see Filter
  * @see DropWhile
  */
-public final class TakeWhile implements Fn2, Iterable, Iterable> {
+public final class TakeWhile implements Fn2, Iterable, Iterable> {
 
     private static final TakeWhile INSTANCE = new TakeWhile<>();
 
@@ -23,7 +21,7 @@ private TakeWhile() {
     }
 
     @Override
-    public Iterable checkedApply(Function predicate, Iterable as) {
+    public Iterable checkedApply(Fn1 predicate, Iterable as) {
         return new PredicatedTakingIterable<>(predicate, as);
     }
 
@@ -32,11 +30,11 @@ public static  TakeWhile takeWhile() {
         return (TakeWhile) INSTANCE;
     }
 
-    public static  Fn1, Iterable> takeWhile(Function predicate) {
+    public static  Fn1, Iterable> takeWhile(Fn1 predicate) {
         return TakeWhile.takeWhile().apply(predicate);
     }
 
-    public static  Iterable takeWhile(Function predicate, Iterable as) {
+    public static  Iterable takeWhile(Fn1 predicate, Iterable as) {
         return TakeWhile.takeWhile(predicate).apply(as);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java
index 3e2fb05e1..535d90e0a 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollection.java
@@ -1,20 +1,20 @@
 package com.jnape.palatable.lambda.functions.builtin.fn2;
 
+import com.jnape.palatable.lambda.functions.Fn0;
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
 
 import java.util.Collection;
-import java.util.function.Supplier;
 
 /**
- * Given a {@link Supplier} of some {@link Collection} C, create an instance of C and add
- * all of the elements in the provided Iterable to the instance. Note that instances of C
- * must support {@link Collection#add} (which is to say, must not throw on invocation).
+ * Given an {@link Fn0} of some {@link Collection} C, create an instance of C and add all of
+ * the elements in the provided Iterable to the instance. Note that instances of C must
+ * support {@link Collection#add} (which is to say, must not throw on invocation).
  *
  * @param  the iterable element type
  * @param  the resulting collection type
  */
-public final class ToCollection> implements Fn2, Iterable, C> {
+public final class ToCollection> implements Fn2, Iterable, C> {
 
     private static final ToCollection INSTANCE = new ToCollection<>();
 
@@ -22,8 +22,8 @@ private ToCollection() {
     }
 
     @Override
-    public C checkedApply(Supplier cSupplier, Iterable as) {
-        C c = cSupplier.get();
+    public C checkedApply(Fn0 cFn0, Iterable as) {
+        C c = cFn0.apply();
         as.forEach(c::add);
         return c;
     }
@@ -33,11 +33,11 @@ public static > ToCollection toCollection() {
         return (ToCollection) INSTANCE;
     }
 
-    public static > Fn1, C> toCollection(Supplier cSupplier) {
-        return ToCollection.toCollection().apply(cSupplier);
+    public static > Fn1, C> toCollection(Fn0 cFn0) {
+        return ToCollection.toCollection().apply(cFn0);
     }
 
-    public static > C toCollection(Supplier cSupplier, Iterable as) {
-        return toCollection(cSupplier).apply(as);
+    public static > C toCollection(Fn0 cFn0, Iterable as) {
+        return toCollection(cFn0).apply(as);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java
index e674673fb..85dad9e41 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMap.java
@@ -1,23 +1,23 @@
 package com.jnape.palatable.lambda.functions.builtin.fn2;
 
+import com.jnape.palatable.lambda.functions.Fn0;
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
 
 import java.util.Map;
-import java.util.function.Supplier;
 
 import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft;
 
 /**
- * Given a {@link Supplier} of some {@link Map} M, create an instance of M and put
- * all of the entries in the provided Iterable into the instance. Note that instances of M
- * must support {@link java.util.Map#put} (which is to say, must not throw on invocation).
+ * Given an {@link Fn0} of some {@link Map} M, create an instance of M and put all of the
+ * entries in the provided Iterable into the instance. Note that instances of M must support
+ * {@link java.util.Map#put} (which is to say, must not throw on invocation).
  *
  * @param  the key element type
  * @param  the value element type
  * @param  the resulting map type
  */
-public final class ToMap> implements Fn2, Iterable>, M> {
+public final class ToMap> implements Fn2, Iterable>, M> {
 
     private static final ToMap INSTANCE = new ToMap<>();
 
@@ -25,11 +25,11 @@ private ToMap() {
     }
 
     @Override
-    public M checkedApply(Supplier mSupplier, Iterable> entries) {
+    public M checkedApply(Fn0 mFn0, Iterable> entries) {
         return foldLeft((m, kv) -> {
             m.put(kv.getKey(), kv.getValue());
             return m;
-        }, mSupplier.get(), entries);
+        }, mFn0.apply(), entries);
     }
 
     @SuppressWarnings("unchecked")
@@ -37,12 +37,12 @@ public static > ToMap toMap() {
         return (ToMap) INSTANCE;
     }
 
-    public static > Fn1>, M> toMap(Supplier mSupplier) {
-        return ToMap.toMap().apply(mSupplier);
+    public static > Fn1>, M> toMap(Fn0 mFn0) {
+        return ToMap.toMap().apply(mFn0);
     }
 
-    public static > M toMap(Supplier mSupplier,
+    public static > M toMap(Fn0 mFn0,
                                                       Iterable> entries) {
-        return toMap(mSupplier).apply(entries);
+        return toMap(mFn0).apply(entries);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java
index e0c63eeb2..aa451768b 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java
@@ -6,8 +6,6 @@
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.iteration.UnfoldingIterator;
 
-import java.util.function.Function;
-
 /**
  * Given an initial seed value and a function that takes the seed type and produces an {@link Maybe}<{@link
  * Tuple2}<X, Seed>>, where the tuple's first slot represents the next Iterable element,
@@ -29,7 +27,7 @@
  * @param  The output Iterable element type
  * @param  The unfolding function input type
  */
-public final class Unfoldr implements Fn2>>, B, Iterable> {
+public final class Unfoldr implements Fn2>>, B, Iterable> {
 
     private static final Unfoldr INSTANCE = new Unfoldr<>();
 
@@ -37,7 +35,7 @@ private Unfoldr() {
     }
 
     @Override
-    public Iterable checkedApply(Function>> fn, B b) {
+    public Iterable checkedApply(Fn1>> fn, B b) {
         return () -> new UnfoldingIterator<>(fn, b);
     }
 
@@ -46,11 +44,11 @@ public static  Unfoldr unfoldr() {
         return (Unfoldr) INSTANCE;
     }
 
-    public static  Fn1> unfoldr(Function>> fn) {
+    public static  Fn1> unfoldr(Fn1>> fn) {
         return Unfoldr.unfoldr().apply(fn);
     }
 
-    public static  Iterable unfoldr(Function>> fn, B b) {
+    public static  Iterable unfoldr(Fn1>> fn, B b) {
         return unfoldr(fn).apply(b);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java
index 8f896e14c..ff41594b1 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Zip.java
@@ -4,6 +4,7 @@
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
 
+import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler;
 import static com.jnape.palatable.lambda.functions.builtin.fn3.ZipWith.zipWith;
 
 /**
@@ -24,7 +25,7 @@ private Zip() {
 
     @Override
     public Iterable> checkedApply(Iterable as, Iterable bs) {
-        return zipWith(Tupler2.tupler().toBiFunction(), as, bs);
+        return zipWith(tupler(), as, bs);
     }
 
     @SuppressWarnings("unchecked")
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java
index db202c66a..3b483aeaf 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java
@@ -1,11 +1,12 @@
 package com.jnape.palatable.lambda.functions.builtin.fn3;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.functions.builtin.fn2.CmpEq;
 import com.jnape.palatable.lambda.functions.specialized.BiPredicate;
 import com.jnape.palatable.lambda.functions.specialized.Predicate;
 
-import java.util.function.Function;
+import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate;
 
 /**
  * Given a mapping function from some type A to some {@link Comparable} type B and two values
@@ -18,7 +19,7 @@
  * @see LTBy
  * @see GTBy
  */
-public final class CmpEqBy> implements Fn3, A, A, Boolean> {
+public final class CmpEqBy> implements Fn3, A, A, Boolean> {
 
     private static final CmpEqBy INSTANCE = new CmpEqBy<>();
 
@@ -26,18 +27,18 @@ private CmpEqBy() {
     }
 
     @Override
-    public Boolean checkedApply(Function compareFn, A x, A y) {
+    public Boolean checkedApply(Fn1 compareFn, A x, A y) {
         return compareFn.apply(x).compareTo(compareFn.apply(y)) == 0;
     }
 
     @Override
-    public BiPredicate apply(Function compareFn) {
+    public BiPredicate apply(Fn1 compareFn) {
         return Fn3.super.apply(compareFn)::apply;
     }
 
     @Override
-    public Predicate apply(Function compareFn, A x) {
-        return Fn3.super.apply(compareFn, x)::apply;
+    public Predicate apply(Fn1 compareFn, A x) {
+        return predicate(Fn3.super.apply(compareFn, x));
     }
 
     @SuppressWarnings("unchecked")
@@ -45,15 +46,15 @@ public static > CmpEqBy cmpEqBy() {
         return (CmpEqBy) INSTANCE;
     }
 
-    public static > BiPredicate cmpEqBy(Function compareFn) {
+    public static > BiPredicate cmpEqBy(Fn1 compareFn) {
         return CmpEqBy.cmpEqBy().apply(compareFn);
     }
 
-    public static > Predicate cmpEqBy(Function compareFn, A x) {
+    public static > Predicate cmpEqBy(Fn1 compareFn, A x) {
         return CmpEqBy.cmpEqBy(compareFn).apply(x);
     }
 
-    public static > Boolean cmpEqBy(Function compareFn, A x, A y) {
+    public static > Boolean cmpEqBy(Fn1 compareFn, A x, A y) {
         return cmpEqBy(compareFn, x).apply(y);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java
index d7f9a24e6..e05b1bcf0 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldLeft.java
@@ -4,12 +4,10 @@
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.functions.Fn3;
 
-import java.util.function.BiFunction;
-
 /**
- * Given an Iterable of As, a starting value B, and a {@link
- * BiFunction}<B, A, B>, iteratively accumulate over the Iterable, ultimately returning a
- * final B value. If the Iterable is empty, just return the starting B value.
+ * Given an Iterable of As, a starting value B, and a
+ * {@link Fn2}<B, A, B>, iteratively accumulate over the Iterable, ultimately returning
+ * a final B value. If the Iterable is empty, just return the starting B value.
  * Note that, as the name implies, this function accumulates from left to right, such that foldLeft(f, 0,
  * asList(1, 2, 3, 4, 5)) is evaluated as f(f(f(f(f(0, 1), 2), 3), 4), 5).
  * 

@@ -20,15 +18,15 @@ * @param The accumulation type * @see FoldRight */ -public final class FoldLeft implements Fn3, B, Iterable, B> { +public final class FoldLeft implements Fn3, B, Iterable, B> { - private static final FoldLeft INSTANCE = new FoldLeft<>(); + private static final FoldLeft INSTANCE = new FoldLeft<>(); private FoldLeft() { } @Override - public B checkedApply(BiFunction fn, B acc, Iterable as) { + public B checkedApply(Fn2 fn, B acc, Iterable as) { B accumulation = acc; for (A a : as) accumulation = fn.apply(accumulation, a); @@ -40,15 +38,15 @@ public static FoldLeft foldLeft() { return (FoldLeft) INSTANCE; } - public static Fn2, B> foldLeft(BiFunction fn) { + public static Fn2, B> foldLeft(Fn2 fn) { return FoldLeft.foldLeft().apply(fn); } - public static Fn1, B> foldLeft(BiFunction fn, B acc) { + public static Fn1, B> foldLeft(Fn2 fn, B acc) { return FoldLeft.foldLeft(fn).apply(acc); } - public static B foldLeft(BiFunction fn, B acc, Iterable as) { + public static B foldLeft(Fn2 fn, B acc, Iterable as) { return FoldLeft.foldLeft(fn, acc).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java index 4086204ed..21116dd84 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRight.java @@ -5,18 +5,16 @@ import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functor.builtin.Lazy; -import java.util.function.BiFunction; - import static com.jnape.palatable.lambda.functions.builtin.fn2.LazyRec.lazyRec; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** * Given an Iterable of As, a starting {@link Lazy lazy} value B, and a - * {@link BiFunction}<A, {@link Lazy}<B>, {@link Lazy}<B>>, iteratively accumulate over - * the Iterable, ultimately returning a final {@link Lazy}<B> value. If the - * Iterable is empty, just return the starting {@link Lazy}<B> value. - * This function is computationally the iterative inverse of {@link FoldLeft}, but uses {@link Lazy} to allow support - * stack-safe execution. + * {@link Fn2}<A, {@link Lazy}<B>, {@link Lazy}<B>>, iteratively accumulate over the + * Iterable, ultimately returning a final {@link Lazy}<B> value. If the + * Iterable is empty, just return the starting {@link Lazy}<B> value. This function is + * computationally the iterative inverse of {@link FoldLeft}, but uses {@link Lazy} to allow support stack-safe + * execution. *

* Example: *

@@ -39,7 +37,7 @@
  * @see FoldLeft
  */
 public final class FoldRight implements
-        Fn3, ? extends Lazy>, Lazy, Iterable, Lazy> {
+        Fn3, ? extends Lazy>, Lazy, Iterable, Lazy> {
 
     private static final FoldRight INSTANCE = new FoldRight<>();
 
@@ -47,7 +45,7 @@ private FoldRight() {
     }
 
     @Override
-    public Lazy checkedApply(BiFunction, ? extends Lazy> fn, Lazy acc,
+    public Lazy checkedApply(Fn2, ? extends Lazy> fn, Lazy acc,
                                 Iterable as) {
         return lazyRec((f, lazyIt) -> lazyIt.flatMap(it -> it.hasNext()
                                                            ? fn.apply(it.next(), f.apply(lazy(it)))
@@ -61,17 +59,17 @@ public static  FoldRight foldRight() {
     }
 
     public static  Fn2, Iterable, Lazy> foldRight(
-            BiFunction, ? extends Lazy> fn) {
+            Fn2, ? extends Lazy> fn) {
         return FoldRight.foldRight().apply(fn);
     }
 
     public static  Fn1, Lazy> foldRight(
-            BiFunction, ? extends Lazy> fn,
+            Fn2, ? extends Lazy> fn,
             Lazy acc) {
         return FoldRight.foldRight(fn).apply(acc);
     }
 
-    public static  Lazy foldRight(BiFunction, ? extends Lazy> fn, Lazy acc,
+    public static  Lazy foldRight(Fn2, ? extends Lazy> fn, Lazy acc,
                                            Iterable as) {
         return FoldRight.foldRight(fn, acc).apply(as);
     }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java
index 0a6bf807d..cb9b45168 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java
@@ -1,11 +1,12 @@
 package com.jnape.palatable.lambda.functions.builtin.fn3;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.functions.builtin.fn2.GT;
 import com.jnape.palatable.lambda.functions.specialized.BiPredicate;
 import com.jnape.palatable.lambda.functions.specialized.Predicate;
 
-import java.util.function.Function;
+import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate;
 
 /**
  * Given a mapping function from some type A to some {@link Comparable} type B and two values
@@ -17,7 +18,7 @@
  * @see GT
  * @see LTBy
  */
-public final class GTBy> implements Fn3, A, A, Boolean> {
+public final class GTBy> implements Fn3, A, A, Boolean> {
 
     private static final GTBy INSTANCE = new GTBy<>();
 
@@ -25,18 +26,18 @@ private GTBy() {
     }
 
     @Override
-    public Boolean checkedApply(Function compareFn, A y, A x) {
+    public Boolean checkedApply(Fn1 compareFn, A y, A x) {
         return compareFn.apply(x).compareTo(compareFn.apply(y)) > 0;
     }
 
     @Override
-    public BiPredicate apply(Function compareFn) {
+    public BiPredicate apply(Fn1 compareFn) {
         return Fn3.super.apply(compareFn)::apply;
     }
 
     @Override
-    public Predicate apply(Function compareFn, A x) {
-        return Fn3.super.apply(compareFn, x)::apply;
+    public Predicate apply(Fn1 compareFn, A x) {
+        return predicate(Fn3.super.apply(compareFn, x));
     }
 
     @SuppressWarnings("unchecked")
@@ -44,15 +45,15 @@ public static > GTBy gtBy() {
         return (GTBy) INSTANCE;
     }
 
-    public static > BiPredicate gtBy(Function fn) {
+    public static > BiPredicate gtBy(Fn1 fn) {
         return GTBy.gtBy().apply(fn);
     }
 
-    public static > Predicate gtBy(Function fn, A y) {
+    public static > Predicate gtBy(Fn1 fn, A y) {
         return GTBy.gtBy(fn).apply(y);
     }
 
-    public static > Boolean gtBy(Function fn, A y, A x) {
+    public static > Boolean gtBy(Fn1 fn, A y, A x) {
         return gtBy(fn, y).apply(x);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java
index 6c956e366..30ef09852 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java
@@ -1,13 +1,13 @@
 package com.jnape.palatable.lambda.functions.builtin.fn3;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.functions.builtin.fn2.GTE;
 import com.jnape.palatable.lambda.functions.specialized.BiPredicate;
 import com.jnape.palatable.lambda.functions.specialized.Predicate;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy;
+import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate;
 
 /**
  * Given a mapping function from some type A to some {@link Comparable} type B and two values
@@ -20,7 +20,7 @@
  * @see GTE
  * @see LTEBy
  */
-public final class GTEBy> implements Fn3, A, A, Boolean> {
+public final class GTEBy> implements Fn3, A, A, Boolean> {
 
     private static final GTEBy INSTANCE = new GTEBy<>();
 
@@ -28,18 +28,18 @@ private GTEBy() {
     }
 
     @Override
-    public Boolean checkedApply(Function compareFn, A y, A x) {
+    public Boolean checkedApply(Fn1 compareFn, A y, A x) {
         return GTBy.gtBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x);
     }
 
     @Override
-    public BiPredicate apply(Function compareFn) {
+    public BiPredicate apply(Fn1 compareFn) {
         return Fn3.super.apply(compareFn)::apply;
     }
 
     @Override
-    public Predicate apply(Function compareFn, A y) {
-        return Fn3.super.apply(compareFn, y)::apply;
+    public Predicate apply(Fn1 compareFn, A y) {
+        return predicate(Fn3.super.apply(compareFn, y));
     }
 
     @SuppressWarnings("unchecked")
@@ -47,15 +47,15 @@ public static > GTEBy gteBy() {
         return (GTEBy) INSTANCE;
     }
 
-    public static > BiPredicate gteBy(Function fn) {
+    public static > BiPredicate gteBy(Fn1 fn) {
         return GTEBy.gteBy().apply(fn);
     }
 
-    public static > Predicate gteBy(Function fn, A y) {
+    public static > Predicate gteBy(Fn1 fn, A y) {
         return GTEBy.gteBy(fn).apply(y);
     }
 
-    public static > Boolean gteBy(Function fn, A y, A x) {
+    public static > Boolean gteBy(Fn1 fn, A y, A x) {
         return gteBy(fn, y).apply(x);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java
index be547f38b..c442d9871 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java
@@ -1,11 +1,12 @@
 package com.jnape.palatable.lambda.functions.builtin.fn3;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.functions.builtin.fn2.LT;
 import com.jnape.palatable.lambda.functions.specialized.BiPredicate;
 import com.jnape.palatable.lambda.functions.specialized.Predicate;
 
-import java.util.function.Function;
+import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate;
 
 /**
  * Given a mapping function from some type A to some {@link Comparable} type B and two values
@@ -17,26 +18,26 @@
  * @see LT
  * @see GTBy
  */
-public final class LTBy> implements Fn3, A, A, Boolean> {
+public final class LTBy> implements Fn3, A, A, Boolean> {
 
-    private static final LTBy INSTANCE = new LTBy<>();
+    private static final LTBy INSTANCE = new LTBy<>();
 
     private LTBy() {
     }
 
     @Override
-    public Boolean checkedApply(Function compareFn, A y, A x) {
+    public Boolean checkedApply(Fn1 compareFn, A y, A x) {
         return compareFn.apply(x).compareTo(compareFn.apply(y)) < 0;
     }
 
     @Override
-    public BiPredicate apply(Function compareFn) {
+    public BiPredicate apply(Fn1 compareFn) {
         return Fn3.super.apply(compareFn)::apply;
     }
 
     @Override
-    public Predicate apply(Function compareFn, A y) {
-        return Fn3.super.apply(compareFn, y)::apply;
+    public Predicate apply(Fn1 compareFn, A y) {
+        return predicate(Fn3.super.apply(compareFn, y));
     }
 
     @SuppressWarnings("unchecked")
@@ -44,15 +45,15 @@ public static > LTBy ltBy() {
         return (LTBy) INSTANCE;
     }
 
-    public static > BiPredicate ltBy(Function fn) {
+    public static > BiPredicate ltBy(Fn1 fn) {
         return LTBy.ltBy().apply(fn);
     }
 
-    public static > Predicate ltBy(Function fn, A y) {
+    public static > Predicate ltBy(Fn1 fn, A y) {
         return LTBy.ltBy(fn).apply(y);
     }
 
-    public static > Boolean ltBy(Function fn, A y, A x) {
+    public static > Boolean ltBy(Fn1 fn, A y, A x) {
         return ltBy(fn, y).apply(x);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java
index 2dda81ce4..bc755470d 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java
@@ -1,12 +1,11 @@
 package com.jnape.palatable.lambda.functions.builtin.fn3;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.functions.builtin.fn2.LTE;
 import com.jnape.palatable.lambda.functions.specialized.BiPredicate;
 import com.jnape.palatable.lambda.functions.specialized.Predicate;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy;
 
 /**
@@ -20,25 +19,25 @@
  * @see LTE
  * @see GTEBy
  */
-public final class LTEBy> implements Fn3, A, A, Boolean> {
+public final class LTEBy> implements Fn3, A, A, Boolean> {
 
-    private static final LTEBy INSTANCE = new LTEBy<>();
+    private static final LTEBy INSTANCE = new LTEBy<>();
 
     private LTEBy() {
     }
 
     @Override
-    public Boolean checkedApply(Function compareFn, A y, A x) {
+    public Boolean checkedApply(Fn1 compareFn, A y, A x) {
         return LTBy.ltBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x);
     }
 
     @Override
-    public BiPredicate apply(Function compareFn) {
+    public BiPredicate apply(Fn1 compareFn) {
         return Fn3.super.apply(compareFn)::apply;
     }
 
     @Override
-    public Predicate apply(Function compareFn, A y) {
+    public Predicate apply(Fn1 compareFn, A y) {
         return Fn3.super.apply(compareFn, y)::apply;
     }
 
@@ -47,15 +46,15 @@ public static > LTEBy lteBy() {
         return (LTEBy) INSTANCE;
     }
 
-    public static > BiPredicate lteBy(Function fn) {
+    public static > BiPredicate lteBy(Fn1 fn) {
         return LTEBy.lteBy().apply(fn);
     }
 
-    public static > Predicate lteBy(Function fn, A y) {
+    public static > Predicate lteBy(Fn1 fn, A y) {
         return LTEBy.lteBy(fn).apply(y);
     }
 
-    public static > Boolean lteBy(Function fn, A y, A x) {
+    public static > Boolean lteBy(Fn1 fn, A y, A x) {
         return lteBy(fn, y).apply(x);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java
index fbfc78c06..e83048652 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java
@@ -5,10 +5,8 @@
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.functor.Applicative;
 
-import java.util.function.BiFunction;
-
 /**
- * Lift into and apply a {@link BiFunction} to two {@link Applicative} values, returning the result inside the same
+ * Lift into and apply an {@link Fn2} to two {@link Applicative} values, returning the result inside the same
  * {@link Applicative} context. Functionally equivalent to appB.zip(appA.fmap(fn)).
  *
  * @param     the function's first argument type
@@ -24,7 +22,7 @@ public final class LiftA2,
         AppA extends Applicative,
         AppB extends Applicative,
         AppC extends Applicative> implements
-        Fn3, AppA, AppB, AppC> {
+        Fn3, AppA, AppB, AppC> {
 
     private static final LiftA2 INSTANCE = new LiftA2<>();
 
@@ -32,8 +30,8 @@ private LiftA2() {
     }
 
     @Override
-    public AppC checkedApply(BiFunction fn, AppA appA, AppB appB) {
-        return appB.zip(appA.fmap(Fn2.fn2(fn))).coerce();
+    public AppC checkedApply(Fn2 fn, AppA appA, AppB appB) {
+        return appB.zip(appA.fmap(fn)).coerce();
     }
 
     @SuppressWarnings("unchecked")
@@ -46,20 +44,20 @@ AppC extends Applicative> LiftA2 liftA2(
     public static , AppA extends Applicative,
             AppB extends Applicative,
             AppC extends Applicative> Fn2 liftA2(
-            BiFunction fn) {
+            Fn2 fn) {
         return LiftA2.liftA2().apply(fn);
     }
 
     public static , AppA extends Applicative,
             AppB extends Applicative,
-            AppC extends Applicative> Fn1 liftA2(BiFunction fn,
+            AppC extends Applicative> Fn1 liftA2(Fn2 fn,
                                                                      AppA appA) {
         return LiftA2.liftA2(fn).apply(appA);
     }
 
     public static , AppA extends Applicative,
             AppB extends Applicative,
-            AppC extends Applicative> AppC liftA2(BiFunction fn,
+            AppC extends Applicative> AppC liftA2(Fn2 fn,
                                                           AppA appA,
                                                           AppB appB) {
         return LiftA2.liftA2(fn, appA).apply(appB);
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java
index f99e6ec8c..49f77d96c 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java
@@ -5,28 +5,27 @@
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.iteration.ScanningIterator;
 
-import java.util.function.BiFunction;
-
 /**
- * Given an Iterable of As, a starting value B, and a {@link
- * BiFunction}<B, A, B>, iteratively accumulate over the Iterable, collecting each function
- * application result, finally returning an Iterable of all the results. Note that, as the name implies,
- * this function accumulates from left to right, such that scanLeft(f, 0, asList(1,2,3,4,5)) is evaluated
- * as 0, f(0, 1), f(f(0, 1), 2), f(f(f(0, 1), 2), 3), f(f(f(f(0, 1), 2), 3), 4), f(f(f(f(f(0, 1), 2), 3), 4), 5).
+ * Given an Iterable of As, a starting value B, and a
+ * {@link Fn2}<B, A, B>, iteratively accumulate over the Iterable, collecting each
+ * function application result, finally returning an Iterable of all the results. Note that, as the name
+ * implies, this function accumulates from left to right, such that scanLeft(f, 0, asList(1,2,3,4,5)) is
+ * evaluated as 0, f(0, 1), f(f(0, 1), 2), f(f(f(0, 1), 2), 3), f(f(f(f(0, 1), 2), 3), 4), f(f(f(f(f(0, 1), 2),
+ * 3), 4), 5).
  *
  * @param  The Iterable element type
  * @param  The accumulation type
  * @see FoldLeft
  */
-public final class ScanLeft implements Fn3, B, Iterable, Iterable> {
+public final class ScanLeft implements Fn3, B, Iterable, Iterable> {
 
-    private static final ScanLeft INSTANCE = new ScanLeft<>();
+    private static final ScanLeft INSTANCE = new ScanLeft<>();
 
     private ScanLeft() {
     }
 
     @Override
-    public Iterable checkedApply(BiFunction fn, B b, Iterable as) {
+    public Iterable checkedApply(Fn2 fn, B b, Iterable as) {
         return () -> new ScanningIterator<>(fn, b, as.iterator());
     }
 
@@ -35,15 +34,15 @@ public static  ScanLeft scanLeft() {
         return (ScanLeft) INSTANCE;
     }
 
-    public static  Fn2, Iterable> scanLeft(BiFunction fn) {
+    public static  Fn2, Iterable> scanLeft(Fn2 fn) {
         return ScanLeft.scanLeft().apply(fn);
     }
 
-    public static  Fn1, Iterable> scanLeft(BiFunction fn, B b) {
+    public static  Fn1, Iterable> scanLeft(Fn2 fn, B b) {
         return ScanLeft.scanLeft(fn).apply(b);
     }
 
-    public static  Iterable scanLeft(BiFunction fn, B b, Iterable as) {
+    public static  Iterable scanLeft(Fn2 fn, B b, Iterable as) {
         return ScanLeft.scanLeft(fn, b).apply(as);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java
index 10db14166..c23277e63 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Times.java
@@ -4,8 +4,6 @@
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.functions.Fn3;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate;
 import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft;
 
@@ -20,7 +18,7 @@
  *
  * @param  the input and output type
  */
-public final class Times implements Fn3, A, A> {
+public final class Times implements Fn3, A, A> {
 
     private static final Times INSTANCE = new Times<>();
 
@@ -28,7 +26,7 @@ private Times() {
     }
 
     @Override
-    public A checkedApply(Integer n, Function fn, A a) {
+    public A checkedApply(Integer n, Fn1 fn, A a) {
         if (n < 0)
             throw new IllegalStateException("n must not be less than 0");
 
@@ -40,15 +38,15 @@ public static  Times times() {
         return (Times) INSTANCE;
     }
 
-    public static  Fn2, A, A> times(Integer n) {
+    public static  Fn2, A, A> times(Integer n) {
         return Times.times().apply(n);
     }
 
-    public static  Fn1 times(Integer n, Function fn) {
+    public static  Fn1 times(Integer n, Fn1 fn) {
         return Times.times(n).apply(fn);
     }
 
-    public static  A times(Integer n, Function fn, A a) {
+    public static  A times(Integer n, Fn1 fn, A a) {
         return Times.times(n, fn).apply(a);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java
index 218b1db48..96c072bd2 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java
@@ -17,7 +17,7 @@
  * @param  The output Iterable element type
  * @see com.jnape.palatable.lambda.functions.builtin.fn2.Zip
  */
-public final class ZipWith implements Fn3, Iterable, Iterable, Iterable> {
+public final class ZipWith implements Fn3, Iterable, Iterable, Iterable> {
 
     private static final ZipWith INSTANCE = new ZipWith<>();
 
@@ -25,7 +25,7 @@ private ZipWith() {
     }
 
     @Override
-    public Iterable checkedApply(BiFunction zipper, Iterable as,
+    public Iterable checkedApply(Fn2 zipper, Iterable as,
                                     Iterable bs) {
         return () -> new ZippingIterator<>(zipper, as.iterator(), bs.iterator());
     }
@@ -36,16 +36,16 @@ public static  ZipWith zipWith() {
     }
 
     public static  Fn2, Iterable, Iterable> zipWith(
-            BiFunction zipper) {
+            Fn2 zipper) {
         return ZipWith.zipWith().apply(zipper);
     }
 
-    public static  Fn1, Iterable> zipWith(BiFunction zipper,
+    public static  Fn1, Iterable> zipWith(Fn2 zipper,
                                                                   Iterable as) {
         return ZipWith.zipWith(zipper).apply(as);
     }
 
-    public static  Iterable zipWith(BiFunction zipper, Iterable as,
+    public static  Iterable zipWith(Fn2 zipper, Iterable as,
                                                 Iterable bs) {
         return ZipWith.zipWith(zipper, as).apply(bs);
     }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java
index 38f0bbe3e..70336b79a 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElse.java
@@ -5,9 +5,8 @@
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.functions.Fn4;
 
-import java.util.function.Function;
-
-public final class IfThenElse implements Fn4, Function, Function, A, B> {
+public final class IfThenElse implements
+        Fn4, Fn1, Fn1, A, B> {
 
     private static final IfThenElse INSTANCE = new IfThenElse<>();
 
@@ -15,8 +14,8 @@ private IfThenElse() {
     }
 
     @Override
-    public B checkedApply(Function predicate, Function thenCase,
-                          Function elseCase, A a) {
+    public B checkedApply(Fn1 predicate, Fn1 thenCase,
+                          Fn1 elseCase, A a) {
         return predicate.apply(a) ? thenCase.apply(a) : elseCase.apply(a);
     }
 
@@ -25,26 +24,24 @@ public static  IfThenElse ifThenElse() {
         return (IfThenElse) INSTANCE;
     }
 
-    public static  Fn3, Function, A, B> ifThenElse(
-            Function predicate) {
+    public static  Fn3, Fn1, A, B> ifThenElse(
+            Fn1 predicate) {
         return IfThenElse.ifThenElse().apply(predicate);
     }
 
-    public static  Fn2, A, B> ifThenElse(
-            Function predicate, Function thenCase) {
+    public static  Fn2, A, B> ifThenElse(Fn1 predicate,
+                                                                           Fn1 thenCase) {
         return IfThenElse.ifThenElse(predicate).apply(thenCase);
     }
 
-    public static  Fn1 ifThenElse(
-            Function predicate, Function thenCase,
-            Function elseCase) {
+    public static  Fn1 ifThenElse(Fn1 predicate,
+                                              Fn1 thenCase,
+                                              Fn1 elseCase) {
         return IfThenElse.ifThenElse(predicate, thenCase).apply(elseCase);
     }
 
-    public static  B ifThenElse(
-            Function predicate, Function thenCase,
-            Function elseCase,
-            A a) {
+    public static  B ifThenElse(Fn1 predicate, Fn1 thenCase,
+                                      Fn1 elseCase, A a) {
         return ifThenElse(predicate, thenCase, elseCase).apply(a);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java
index 2da5fb3b2..fa5a0844c 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java
@@ -1,5 +1,6 @@
 package com.jnape.palatable.lambda.functions.builtin.fn4;
 
+import com.jnape.palatable.lambda.functions.Fn0;
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.functions.Fn3;
@@ -9,27 +10,29 @@
 
 import java.time.Duration;
 import java.time.Instant;
-import java.util.function.Supplier;
 
 import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
 import static java.util.Collections.singleton;
 
 /**
- * Given a {@link Supplier} of {@link Instant Instants} (presumably backed by a clock), a limit, a {@link
- * Duration}, and an {@link Iterable} as, return an {@link Iterable} that iterates as
- * according to the threshold specified by the limit per duration, using the {@link Supplier} to advance time.
+ * Given an {@link Fn0} of {@link Instant Instants} (presumably backed by a clock), a limit, a
+ * {@link Duration}, and an {@link Iterable} as, return an {@link Iterable} that iterates as
+ * according to the threshold specified by the limit per duration, using the {@link Fn0} to advance time.
  * 

* As an example, the following will print at most 10 elements per second: *


- * rateLimit(Clock.systemUTC()::instant, 10L, Duration.ofSeconds(1), iterate(x -> x + 1, 1)).forEach(System.out::println);
+ * rateLimit(Clock.systemUTC()::instant, 10L, Duration.ofSeconds(1), iterate(x -> x + 1, 1))
+ *     .forEach(System.out::println);
  * 
* Currying allows different rate limits to be combined naturally: *

  * Iterable<Integer> elements = iterate(x -> x + 1, 1);
  *
- * Supplier<Instant> instantSupplier = Clock.systemUTC()::instant;
- * Fn1<Iterable<Integer>, Iterable<Integer>> tenPerSecond = rateLimit(instantSupplier, 10L, Duration.ofSeconds(1));
- * Fn1<Iterable<Integer>, Iterable<Integer>> oneHundredEveryTwoMinutes = rateLimit(instantSupplier, 100L, Duration.ofMinutes(2));
+ * Supplier<Instant> instantFn0 = Clock.systemUTC()::instant;
+ * Fn1<Iterable<Integer>, Iterable<Integer>> tenPerSecond =
+ *     rateLimit(instantFn0, 10L, Duration.ofSeconds(1));
+ * Fn1<Iterable<Integer>, Iterable<Integer>> oneHundredEveryTwoMinutes =
+ *     rateLimit(instantFn0, 100L, Duration.ofMinutes(2));
  *
  * tenPerSecond.fmap(oneHundredEveryTwoMinutes).apply(elements).forEach(System.out::println);
  * 
@@ -45,7 +48,7 @@ * * @param
the {@link Iterable} element type */ -public final class RateLimit implements Fn4, Long, Duration, Iterable, Iterable> { +public final class RateLimit implements Fn4, Long, Duration, Iterable, Iterable> { private static final RateLimit INSTANCE = new RateLimit<>(); @@ -53,11 +56,11 @@ private RateLimit() { } @Override - public Iterable checkedApply(Supplier instantSupplier, Long limit, Duration duration, Iterable as) { + public Iterable checkedApply(Fn0 instantFn0, Long limit, Duration duration, Iterable as) { if (limit < 1) throw new IllegalArgumentException("Limit must be greater than 0: " + limit); - return new RateLimitingIterable<>(as, singleton(tuple(limit, duration, instantSupplier))); + return new RateLimitingIterable<>(as, singleton(tuple(limit, duration, instantFn0))); } @SuppressWarnings("unchecked") @@ -65,21 +68,19 @@ public static RateLimit rateLimit() { return (RateLimit) INSTANCE; } - public static Fn3, Iterable> rateLimit(Supplier instantSupplier) { - return RateLimit.rateLimit().apply(instantSupplier); + public static Fn3, Iterable> rateLimit(Fn0 instantFn0) { + return RateLimit.rateLimit().apply(instantFn0); } - public static Fn2, Iterable> rateLimit(Supplier instantSupplier, Long limit) { - return RateLimit.rateLimit(instantSupplier).apply(limit); + public static Fn2, Iterable> rateLimit(Fn0 instantFn0, Long limit) { + return RateLimit.rateLimit(instantFn0).apply(limit); } - public static Fn1, Iterable> rateLimit(Supplier instantSupplier, Long limit, - Duration duration) { - return RateLimit.rateLimit(instantSupplier, limit).apply(duration); + public static Fn1, Iterable> rateLimit(Fn0 instantFn0, Long limit, Duration duration) { + return RateLimit.rateLimit(instantFn0, limit).apply(duration); } - public static Iterable rateLimit(Supplier instantSupplier, Long limit, Duration duration, - Iterable as) { - return RateLimit.rateLimit(instantSupplier, limit, duration).apply(as); + public static Iterable rateLimit(Fn0 instantFn0, Long limit, Duration duration, Iterable as) { + return RateLimit.rateLimit(instantFn0, limit, duration).apply(as); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java index afef70f6d..29ddc08c8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java @@ -1,13 +1,13 @@ package com.jnape.palatable.lambda.functions.recursion; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; /** * Specialized {@link CoProduct2} representing the possible results of a primitive recursive function. @@ -30,25 +30,24 @@ public RecursiveResult invert() { @Override @SuppressWarnings("unchecked") - public RecursiveResult biMapL(Function fn) { + public RecursiveResult biMapL(Fn1 fn) { return (RecursiveResult) Bifunctor.super.biMapL(fn); } @Override @SuppressWarnings("unchecked") - public RecursiveResult biMapR(Function fn) { + public RecursiveResult biMapR(Fn1 fn) { return (RecursiveResult) Bifunctor.super.biMapR(fn); } @Override - public RecursiveResult biMap(Function lFn, - Function rFn) { + public RecursiveResult biMap(Fn1 lFn, + Fn1 rFn) { return match(a -> recurse(lFn.apply(a)), b -> terminate(rFn.apply(b))); } @Override - public RecursiveResult flatMap( - Function>> f) { + public RecursiveResult flatMap(Fn1>> f) { return match(RecursiveResult::recurse, b -> f.apply(b).coerce()); } @@ -58,13 +57,12 @@ public RecursiveResult pure(C c) { } @Override - public RecursiveResult fmap(Function fn) { + public RecursiveResult fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @Override - public RecursiveResult zip( - Applicative, RecursiveResult> appFn) { + public RecursiveResult zip(Applicative, RecursiveResult> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -79,11 +77,10 @@ public RecursiveResult discardR(Applicative> } @Override - @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return match(__ -> pure.apply(coerce()), b -> fn.apply(b).fmap(this::pure).fmap(RecursiveResult::coerce).coerce()); } @@ -104,7 +101,7 @@ private Recurse(A a) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return aFn.apply(a); } @@ -134,7 +131,7 @@ private Terminate(B b) { } @Override - public R match(Function aFn, Function bFn) { + public R match(Fn1 aFn, Fn1 bFn) { return bFn.apply(b); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java index 70e8f4fd7..6637219ec 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/Trampoline.java @@ -7,25 +7,23 @@ import com.jnape.palatable.lambda.functions.recursion.RecursiveResult.Recurse; import com.jnape.palatable.lambda.functions.recursion.RecursiveResult.Terminate; -import java.util.function.Function; - /** - * Given a {@link Function}<A, {@link CoProduct2}<A, B, ?>> (analogous to "recurse" and - * "return" tail position instructions, respectively), produce a {@link Function}<A, B> that - * unrolls the original function by iteratively passing each result that matches the input (A) back - * to the original function, and then terminating on and returning the first output (B). + * Given an {@link Fn1}<A, {@link CoProduct2}<A, B, ?>> (analogous to "recurse" and "return" + * tail position instructions, respectively), produce a {@link Fn1}<A, B> that unrolls the original + * function by iteratively passing each result that matches the input (A) back to the original function, + * and then terminating on and returning the first output (B). *

* This is isomorphic to - though presumably faster than - taking the last element of an {@link Unfoldr} call. * * @param the trampolined function's input type * @param the trampolined function's output type */ -public final class Trampoline implements Fn2>, A, B> { +public final class Trampoline implements Fn2>, A, B> { private static final Trampoline INSTANCE = new Trampoline<>(); @Override - public B checkedApply(Function> fn, A a) { + public B checkedApply(Fn1> fn, A a) { RecursiveResult next = fn.apply(a); while (next instanceof Recurse) next = fn.apply(((Recurse) next).a); @@ -37,11 +35,11 @@ public static Trampoline trampoline() { return (Trampoline) INSTANCE; } - public static Fn1 trampoline(Function> fn) { + public static Fn1 trampoline(Fn1> fn) { return Trampoline.trampoline().apply(fn); } - public static B trampoline(Function> fn, A a) { + public static B trampoline(Fn1> fn, A a) { return trampoline(fn).apply(a); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java index 8d28fb290..54d11cd92 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiPredicate.java @@ -1,42 +1,41 @@ package com.jnape.palatable.lambda.functions.specialized; import com.jnape.palatable.lambda.adt.product.Product2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; - -import java.util.function.Function; +import com.jnape.palatable.lambda.functor.Applicative; /** - * A specialized {@link Fn2} that returns a Boolean when fully applied, - * or a {@link Predicate} when partially applied. + * A specialized {@link Fn2} that returns a Boolean when fully applied, or a {@link Predicate} when partially applied. * * @param the first argument type * @param the second argument type */ @FunctionalInterface -public interface BiPredicate extends Fn2, java.util.function.BiPredicate { +public interface BiPredicate extends Fn2 { /** * {@inheritDoc} */ @Override - default boolean test(A a, B b) { - return apply(a, b); + default Predicate apply(A a) { + return Fn2.super.apply(a)::apply; } /** * {@inheritDoc} */ @Override - default Predicate apply(A a) { - return Fn2.super.apply(a)::apply; + default BiPredicate flip() { + return Fn2.super.flip()::apply; } /** * {@inheritDoc} */ @Override - default BiPredicate flip() { - return Fn2.super.flip()::apply; + default BiPredicate discardR(Applicative> appB) { + return Fn2.super.discardR(appB)::apply; } /** @@ -51,7 +50,7 @@ default BiPredicate flip() { * {@inheritDoc} */ @Override - default BiPredicate diMapL(Function fn) { + default BiPredicate diMapL(Fn1 fn) { return Fn2.super.diMapL(fn)::apply; } @@ -59,42 +58,57 @@ default BiPredicate diMapL(Function fn) { * {@inheritDoc} */ @Override - default Fn2 contraMap(Function fn) { + default Fn2 contraMap(Fn1 fn) { return Fn2.super.contraMap(fn)::apply; } /** - * Override of {@link java.util.function.BiPredicate#and(java.util.function.BiPredicate)}, returning an instance of - * BiPredicate for compatibility. Left-to-right composition. + * Left-to-right short-circuiting logical conjunction. * * @param other the biPredicate to test if this one succeeds * @return a biPredicate representing the conjunction of this biPredicate and other */ - @Override - default BiPredicate and(java.util.function.BiPredicate other) { - return (a, b) -> apply(a, b) && other.test(a, b); + default BiPredicate and(BiPredicate other) { + return (a, b) -> apply(a, b) && other.apply(a, b); } /** - * Override of {@link java.util.function.BiPredicate#or(java.util.function.BiPredicate)}, returning an instance of - * BiPredicate for compatibility. Left-to-right composition. + * Left-to-right short-circuiting logical disjunction. * * @param other the biPredicate to test if this one fails * @return a biPredicate representing the disjunction of this biPredicate and other */ - @Override - default BiPredicate or(java.util.function.BiPredicate other) { - return (a, b) -> apply(a, b) || other.test(a, b); + default BiPredicate or(BiPredicate other) { + return (a, b) -> apply(a, b) || other.apply(a, b); } /** - * Override of {@link java.util.function.BiPredicate#negate()}, returning an instance of BiPredicate - * for compatibility. + * Logical negation. * * @return the negation of this biPredicate */ - @Override default BiPredicate negate() { return (a, b) -> !apply(a, b); } + + /** + * Convert this {@link BiPredicate} to a java {@link java.util.function.BiPredicate}. + * + * @return {@link java.util.function.BiPredicate} + */ + default java.util.function.BiPredicate toBiPredicate() { + return this::apply; + } + + /** + * Create a {@link BiPredicate} from a java {@link java.util.function.BiPredicate}. + * + * @param biPredicate the {@link java.util.function.BiPredicate} + * @param the first input type + * @param the second input type + * @return the {@link BiPredicate} + */ + static BiPredicate fromBiPredicate(java.util.function.BiPredicate biPredicate) { + return biPredicate::test; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java index 4fae5b021..ad66e4036 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Kleisli.java @@ -4,11 +4,9 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; -import java.util.function.Function; - /** * The Kleisli arrow of a {@link Monad}, manifest as simply an {@link Fn1}<A, MB>. This can be - * thought of as a fixed, portable {@link Monad#flatMap(Function)}. + * thought of as a fixed, portable {@link Monad#flatMap(Fn1)}. * * @param the input argument type * @param the {@link Monad} unification parameter @@ -43,14 +41,6 @@ default > Kleisli compose(Kleisli before.apply(z).flatMap(this).coerce(); } - /** - * {@inheritDoc} - */ - @Override - default Kleisli compose(Function before) { - return Fn1.super.compose(before)::apply; - } - /** * {@inheritDoc} */ @@ -63,7 +53,7 @@ default Kleisli discardR(Applicative> appB) { * {@inheritDoc} */ @Override - default Kleisli contraMap(Function fn) { + default Kleisli contraMap(Fn1 fn) { return Fn1.super.contraMap(fn)::apply; } @@ -71,7 +61,7 @@ default Kleisli contraMap(Function fn) * {@inheritDoc} */ @Override - default Kleisli diMapL(Function fn) { + default Kleisli diMapL(Fn1 fn) { return Fn1.super.diMapL(fn)::apply; } @@ -86,7 +76,7 @@ default Kleisli diMapL(Function fn) { * @return the function adapted as a {@link Kleisli} arrow */ static , MB extends Monad> Kleisli kleisli( - Function fn) { + Fn1 fn) { return fn::apply; } } \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java index 568e6ca2c..73a867626 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java @@ -1,6 +1,11 @@ package com.jnape.palatable.lambda.functions.specialized; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functions.Effect; +import com.jnape.palatable.lambda.io.IO; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.io.IO.io; /** * As the name might suggest, this is an {@link Effect} that, *ahem*, has no effect. @@ -14,7 +19,8 @@ private Noop() { } @Override - public void checkedAccept(A a) { + public IO checkedApply(A a) throws Throwable { + return io(UNIT); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java index 2138db821..f5e849bb4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Predicate.java @@ -1,96 +1,114 @@ package com.jnape.palatable.lambda.functions.specialized; import com.jnape.palatable.lambda.functions.Fn1; - -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functor.Applicative; /** * A specialized {@link Fn1} that returns a Boolean. * * @param The argument type */ -public interface Predicate extends Fn1, java.util.function.Predicate { +@FunctionalInterface +public interface Predicate extends Fn1 { /** * {@inheritDoc} */ @Override - default boolean test(A a) { - return apply(a); + default Predicate diMapL(Fn1 fn) { + return Fn1.super.diMapL(fn)::apply; } /** - * Override of {@link Function#compose(Function)}, returning an instance of Predicate for - * compatibility. Right-to-left composition. - * - * @param before the function who's return value is this predicate's argument - * @param the new argument type - * @return a new predicate of Z (the new argument type) + * {@inheritDoc} */ @Override - default Predicate compose(Function before) { - return Fn1.super.compose(before)::apply; + default Predicate contraMap(Fn1 fn) { + return Fn1.super.contraMap(fn)::apply; } /** * {@inheritDoc} */ @Override - default Predicate diMapL(Function fn) { - return Fn1.super.diMapL(fn)::apply; + default BiPredicate widen() { + return Fn1.super.widen()::checkedApply; } /** * {@inheritDoc} */ @Override - default Predicate contraMap(Function fn) { - return Fn1.super.contraMap(fn)::apply; + default Predicate discardR(Applicative> appB) { + return Fn1.super.discardR(appB)::checkedApply; + } + + /** + * {@inheritDoc} + */ + @Override + default BiPredicate compose(Fn2 before) { + return Fn1.super.compose(before)::apply; } /** - * Override of {@link java.util.function.Predicate#and(java.util.function.Predicate)}, returning an instance of - * Predicate for compatibility. Left-to-right composition. + * Left-to-right short-circuiting logical conjunction. * * @param other the predicate to test if this one succeeds * @return a predicate representing the conjunction of this predicate and other */ - @Override - default Predicate and(java.util.function.Predicate other) { - return a -> apply(a) && other.test(a); + default Predicate and(Predicate other) { + return a -> apply(a) && other.apply(a); } /** - * Override of {@link java.util.function.Predicate#or(java.util.function.Predicate)}, returning an instance of - * Predicate for compatibility. Left-to-right composition. + * Left-to-right short-circuiting logical disjunction. * * @param other the predicate to test if this one fails * @return a predicate representing the disjunction of this predicate and other */ - @Override - default Predicate or(java.util.function.Predicate other) { - return a -> apply(a) || other.test(a); + default Predicate or(Predicate other) { + return a -> apply(a) || other.apply(a); } /** - * Override of {@link java.util.function.Predicate#negate()}, returning an instance of Predicate for - * compatibility. + * Logical negation. * * @return the negation of this predicate */ - @Override default Predicate negate() { return a -> !apply(a); } /** - * Static factory method to create a predicate from a function. + * Convert this {@link Predicate} to a java {@link java.util.function.Predicate}. + * + * @return the {@link java.util.function.Predicate} + */ + default java.util.function.Predicate toPredicate() { + return this::apply; + } + + /** + * Static factory method to create a predicate from an {@link Fn1}. * - * @param predicate the function + * @param predicate the {@link Fn1} * @param the input type * @return the predicate */ - static Predicate predicate(Function predicate) { + static Predicate predicate(Fn1 predicate) { return predicate::apply; } + + /** + * Create a {@link Predicate} from a java {@link java.util.function.Predicate}. + * + * @param predicate the java {@link java.util.function.Predicate} + * @param the input type + * @return the {@link Predicate} + */ + static Predicate fromPredicate(java.util.function.Predicate predicate) { + return predicate::test; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java new file mode 100644 index 000000000..305fd900a --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java @@ -0,0 +1,54 @@ +package com.jnape.palatable.lambda.functions.specialized; + +import com.jnape.palatable.lambda.functions.specialized.checked.Runtime; +import com.jnape.palatable.lambda.io.IO; + +/** + * An interface used to represent an effect that requires no input and produces no output, and therefore is only + * perceivable through inspection of some unreported state. Only exists because Java target-type inference requires an + * interface, or else this would all be internal, hence the inconveniently-named Ω. + *

+ * Ω should *never* be called directly. + * + * @see IO#io(SideEffect) + */ +public interface SideEffect { + + @SuppressWarnings("NonAsciiCharacters") + void Ω() throws Throwable; + + /** + * Convert this {@link SideEffect} to a java {@link Runnable}. + * + * @return the {@link Runnable} + */ + default Runnable toRunnable() { + return () -> { + try { + Ω(); + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + }; + } + + /** + * Create a {@link SideEffect} from a java {@link Runnable}. + * + * @param runnable the {@link Runnable} + * @return the {@link SideEffect} + */ + static SideEffect fromRunnable(Runnable runnable) { + return runnable::run; + } + + /** + * Static factory method to aid in inference. + * + * @param sideEffect the {@link SideEffect} + * @return the {@link SideEffect} + */ + static SideEffect sideEffect(SideEffect sideEffect) { + return sideEffect; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java deleted file mode 100644 index c3f1bbd51..000000000 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedRunnable.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.jnape.palatable.lambda.functions.specialized.checked; - -import static com.jnape.palatable.lambda.functions.specialized.checked.Runtime.throwChecked; - -/** - * Specialized {@link Runnable} that can throw any {@link Throwable}. - * - * @param The {@link Throwable} type - */ -@FunctionalInterface -public interface CheckedRunnable extends Runnable { - - /** - * A version of {@link Runnable#run()} that can throw checked exceptions. - * - * @throws T any exception that can be thrown by this method - */ - void checkedRun() throws T; - - @Override - default void run() { - try { - checkedRun(); - } catch (Throwable t) { - throw throwChecked(t); - } - } - - /** - * Convenience static factory method for constructing a {@link CheckedRunnable} without an explicit cast or type - * attribution at the call site. - * - * @param runnable the checked runnable - * @param the inferred Throwable type - * @return the checked runnable - */ - static CheckedRunnable checked(CheckedRunnable runnable) { - return runnable::run; - } - -} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java index af08c2a00..4dd634e13 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java @@ -1,9 +1,8 @@ package com.jnape.palatable.lambda.functor; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.builtin.Lazy; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -47,7 +46,7 @@ public interface Applicative> extends Functor * @param the resulting applicative parameter type * @return the mapped applicative */ - Applicative zip(Applicative, App> appFn); + Applicative zip(Applicative, App> appFn); /** * Given a {@link Lazy lazy} instance of this applicative over a mapping function, "zip" the two instances together @@ -61,12 +60,12 @@ public interface Applicative> extends Functor * @see com.jnape.palatable.lambda.adt.Either */ default Lazy> lazyZip( - Lazy, App>> lazyAppFn) { + Lazy, App>> lazyAppFn) { return lazyAppFn.fmap(this::zip); } @Override - default Applicative fmap(Function fn) { + default Applicative fmap(Fn1 fn) { return zip(pure(fn)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java index abdbd7024..bfb201242 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Bifunctor.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functor; -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn1; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -26,7 +26,7 @@ public interface Bifunctor> extends Bounded * @param fn the mapping function * @return a bifunctor over C (the new left parameter) and B (the same right parameter) */ - default Bifunctor biMapL(Function fn) { + default Bifunctor biMapL(Fn1 fn) { return biMap(fn, id()); } @@ -38,7 +38,7 @@ default Bifunctor biMapL(Function fn) { * @param fn the mapping function * @return a bifunctor over A (the same left parameter) and C (the new right parameter) */ - default Bifunctor biMapR(Function fn) { + default Bifunctor biMapR(Fn1 fn) { return biMap(id(), fn); } @@ -52,5 +52,5 @@ default Bifunctor biMapR(Function fn) { * @param rFn the right parameter mapping function * @return a bifunctor over C (the new left parameter type) and D (the new right parameter type) */ - Bifunctor biMap(Function lFn, Function rFn); + Bifunctor biMap(Fn1 lFn, Fn1 rFn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java index 8096ae1cb..057c3bd29 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/BoundedBifunctor.java @@ -1,6 +1,6 @@ package com.jnape.palatable.lambda.functor; -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn1; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -26,24 +26,22 @@ public interface BoundedBifunctor< /** * Covariantly map the left parameter into a value that is covariant to ContraA. * - * @param fn the mapping function * @param the new left parameter type + * @param fn the mapping function * @return a bifunctor of C (the new parameter type) and B (the same right parameter) */ - default BoundedBifunctor biMapL( - Function fn) { + default BoundedBifunctor biMapL(Fn1 fn) { return biMap(fn, id()); } /** * Covariantly map the right parameter into a value that is covariant to ContraB. * - * @param fn the mapping function * @param the new right parameter type + * @param fn the mapping function * @return a bifunctor of A (the same left parameter) and C (the new parameter type) */ - default BoundedBifunctor biMapR( - Function fn) { + default BoundedBifunctor biMapR(Fn1 fn) { return biMap(id(), fn); } @@ -58,6 +56,6 @@ default BoundedBifunctor biMapR( * @return a bifunctor over C (the new left parameter type) and D (the new right parameter type) */ BoundedBifunctor biMap( - Function lFn, - Function rFn); + Fn1 lFn, + Fn1 rFn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java index 97ef582b0..e3ac2783b 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java @@ -1,8 +1,7 @@ package com.jnape.palatable.lambda.functor; import com.jnape.palatable.lambda.adt.hlist.Tuple2; - -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn1; /** * {@link Profunctor} strength in the cartesian product sense: p a b -> p (c ^ a) (c ^ b) for any type @@ -35,20 +34,20 @@ default Cartesian, P> carry() { } @Override - Cartesian diMap(Function lFn, Function rFn); + Cartesian diMap(Fn1 lFn, Fn1 rFn); @Override - default Cartesian diMapL(Function fn) { + default Cartesian diMapL(Fn1 fn) { return (Cartesian) Profunctor.super.diMapL(fn); } @Override - default Cartesian diMapR(Function fn) { + default Cartesian diMapR(Fn1 fn) { return (Cartesian) Profunctor.super.diMapR(fn); } @Override - default Cartesian contraMap(Function fn) { + default Cartesian contraMap(Fn1 fn) { return (Cartesian) Profunctor.super.contraMap(fn); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java b/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java index 41bea7f1c..07bfe13d4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Cocartesian.java @@ -1,8 +1,7 @@ package com.jnape.palatable.lambda.functor; import com.jnape.palatable.lambda.adt.choice.Choice2; - -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn1; /** * {@link Profunctor} strength in the cocartesian coproduct sense: p a b -> p (c v a) (c v b) for any @@ -39,13 +38,13 @@ default Cocartesian, P> choose() { * {@inheritDoc} */ @Override - Cocartesian diMap(Function lFn, Function rFn); + Cocartesian diMap(Fn1 lFn, Fn1 rFn); /** * {@inheritDoc} */ @Override - default Cocartesian diMapL(Function fn) { + default Cocartesian diMapL(Fn1 fn) { return (Cocartesian) Profunctor.super.diMapL(fn); } @@ -53,7 +52,7 @@ default Cocartesian diMapL(Function fn) { * {@inheritDoc} */ @Override - default Cocartesian diMapR(Function fn) { + default Cocartesian diMapR(Fn1 fn) { return (Cocartesian) Profunctor.super.diMapR(fn); } @@ -61,7 +60,7 @@ default Cocartesian diMapR(Function fn) { * {@inheritDoc} */ @Override - default Cocartesian contraMap(Function fn) { + default Cocartesian contraMap(Fn1 fn) { return (Cocartesian) Profunctor.super.contraMap(fn); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java b/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java index bce1d114a..c596b36b0 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Contravariant.java @@ -1,13 +1,14 @@ package com.jnape.palatable.lambda.functor; -import java.util.function.Function; +import com.jnape.palatable.lambda.functions.Fn1; /** * The contravariant functor (or "co-functor"); that is, a functor that maps contravariantly (A <- B) * over its parameter. * Contravariant functors are not necessarily {@link Functor}s. *

- * For more information, read about Contravariant Functors. * * @param the type of the parameter @@ -23,5 +24,5 @@ public interface Contravariant> { * @param the new parameter type * @return the mapped Contravariant functor instance */ - Contravariant contraMap(Function fn); + Contravariant contraMap(Fn1 fn); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Functor.java b/src/main/java/com/jnape/palatable/lambda/functor/Functor.java index 49e5664cd..ec4323641 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Functor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Functor.java @@ -2,8 +2,6 @@ import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; /** @@ -32,7 +30,7 @@ public interface Functor> { * @param fn the mapping function * @return a functor over B (the new parameter type) */ - Functor fmap(Function fn); + Functor fmap(Fn1 fn); /** * Convenience method for coercing this functor instance into another concrete type. Unsafe. diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java index 2c4b45200..b9518d3e4 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Profunctor.java @@ -2,8 +2,6 @@ import com.jnape.palatable.lambda.functions.Fn1; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; /** @@ -33,7 +31,7 @@ public interface Profunctor> extends Contr * @param rFn the right parameter mapping function * @return a profunctor over Z (the new left parameter type) and C (the new right parameter type) */ - Profunctor diMap(Function lFn, Function rFn); + Profunctor diMap(Fn1 lFn, Fn1 rFn); /** * Contravariantly map over the left parameter. @@ -42,7 +40,7 @@ public interface Profunctor> extends Contr * @param fn the mapping function * @return a profunctor over Z (the new left parameter type) and C (the same right parameter type) */ - default Profunctor diMapL(Function fn) { + default Profunctor diMapL(Fn1 fn) { return diMap(fn, id()); } @@ -54,7 +52,7 @@ default Profunctor diMapL(Function fn) { * @param fn the mapping function * @return a profunctor over A (the same left parameter type) and C (the new right parameter type) */ - default Profunctor diMapR(Function fn) { + default Profunctor diMapR(Fn1 fn) { return diMap(id(), fn); } @@ -62,7 +60,7 @@ default Profunctor diMapR(Function fn) { * {@inheritDoc} */ @Override - default Profunctor contraMap(Function fn) { + default Profunctor contraMap(Fn1 fn) { return diMapL(fn); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index 912ca8109..a9a50eb91 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -1,9 +1,9 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; @@ -33,7 +33,7 @@ public , FGA extends Applicative> FGA getCom * {@inheritDoc} */ @Override - public Compose fmap(Function fn) { + public Compose fmap(Fn1 fn) { return new Compose<>(fga.fmap(g -> g.fmap(fn))); } @@ -49,8 +49,8 @@ public Compose pure(B b) { * {@inheritDoc} */ @Override - public Compose zip(Applicative, Compose> appFn) { - return new Compose<>(fga.zip(appFn.>>coerce() + public Compose zip(Applicative, Compose> appFn) { + return new Compose<>(fga.zip(appFn.>>coerce() .getCompose().fmap(gFn -> g -> g.zip(gFn)))); } @@ -59,13 +59,13 @@ public Compose zip(Applicative, Co */ @Override public Lazy> lazyZip( - Lazy, Compose>> lazyAppFn) { + Lazy, Compose>> lazyAppFn) { @SuppressWarnings("RedundantTypeArguments") - Lazy, G>, F>> lazyAppFnCoerced = + Lazy, G>, F>> lazyAppFnCoerced = lazyAppFn - .>>fmap( - Applicative, Compose>::coerce) - .fmap(Compose>::getCompose); + .>>fmap( + Applicative, Compose>::coerce) + .fmap(Compose>::getCompose); return fga.>fmap(upcast()) .>lazyZip(lazyAppFnCoerced.fmap(fgf -> fgf.fmap(gf -> ga -> ga.zip(gf)))) diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index e857013a8..279d04595 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -1,12 +1,12 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; /** * A (surprisingly useful) functor over some phantom type B, retaining a value of type A that @@ -46,7 +46,7 @@ public A runConst() { * @return a Const over A (the same value) and C (the new phantom parameter) */ @Override - public Const fmap(Function fn) { + public Const fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -60,7 +60,7 @@ public Const pure(C c) { * {@inheritDoc} */ @Override - public Const zip(Applicative, Const> appFn) { + public Const zip(Applicative, Const> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -69,7 +69,7 @@ public Const zip(Applicative, Const Lazy> lazyZip( - Lazy, Const>> lazyAppFn) { + Lazy, Const>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } @@ -94,7 +94,7 @@ public Const discardR(Applicative> appB) { */ @Override @SuppressWarnings("unchecked") - public Const flatMap(Function>> f) { + public Const flatMap(Fn1>> f) { return (Const) this; } @@ -104,8 +104,8 @@ public Const flatMap(Function, TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return pure.apply(coerce()); } @@ -113,9 +113,8 @@ AppTrav extends Applicative> AppTrav traverse(Function Const biMapL(Function fn) { - return (Const) Bifunctor.super.biMapL(fn); + public Const biMapL(Fn1 fn) { + return (Const) Bifunctor.super.biMapL(fn); } /** @@ -123,7 +122,7 @@ public Const biMapL(Function fn) { */ @Override @SuppressWarnings("unchecked") - public Const biMapR(Function fn) { + public Const biMapR(Fn1 fn) { return (Const) Bifunctor.super.biMapR(fn); } @@ -131,8 +130,8 @@ public Const biMapR(Function fn) { * {@inheritDoc} */ @Override - public Const biMap(Function lFn, - Function rFn) { + public Const biMap(Fn1 lFn, + Fn1 rFn) { return new Const<>(lFn.apply(a)); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java index 8d7cc82ea..f04050368 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Exchange.java @@ -1,10 +1,9 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.optics.Iso; -import java.util.function.Function; - /** * A profunctor used to extract the isomorphic functions an {@link Iso} is composed of. * @@ -14,10 +13,10 @@ * @param the larger viewed value of an {@link Iso} */ public final class Exchange implements Profunctor> { - private final Function sa; - private final Function bt; + private final Fn1 sa; + private final Fn1 bt; - public Exchange(Function sa, Function bt) { + public Exchange(Fn1 sa, Fn1 bt) { this.sa = sa; this.bt = bt; } @@ -25,18 +24,18 @@ public Exchange(Function sa, FunctionS -> A. * - * @return a {@link Function}<S, A> + * @return an {@link Fn1}<S, A> */ - public Function sa() { + public Fn1 sa() { return sa; } /** * Extract the mapping B -> T. * - * @return a {@link Function}<B, T> + * @return an {@link Fn1}<B, T> */ - public Function bt() { + public Fn1 bt() { return bt; } @@ -44,16 +43,16 @@ public Exchange(Function sa, Function Exchange diMap(Function lFn, - Function rFn) { - return new Exchange<>(lFn.andThen(sa), bt.andThen(rFn)); + public Exchange diMap(Fn1 lFn, + Fn1 rFn) { + return new Exchange<>(lFn.fmap(sa), bt.fmap(rFn)); } /** * {@inheritDoc} */ @Override - public Exchange diMapL(Function fn) { + public Exchange diMapL(Fn1 fn) { return (Exchange) Profunctor.super.diMapL(fn); } @@ -61,7 +60,7 @@ public Exchange diMapL(Function fn) { * {@inheritDoc} */ @Override - public Exchange diMapR(Function fn) { + public Exchange diMapR(Fn1 fn) { return (Exchange) Profunctor.super.diMapR(fn); } @@ -69,7 +68,7 @@ public Exchange diMapR(Function fn) { * {@inheritDoc} */ @Override - public Exchange contraMap(Function fn) { + public Exchange contraMap(Fn1 fn) { return (Exchange) Profunctor.super.contraMap(fn); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java index e17ae005f..bb298596c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java @@ -1,11 +1,11 @@ package com.jnape.palatable.lambda.functor.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; -import java.util.function.Function; /** * A functor over some value of type A that can be mapped over and retrieved later. @@ -33,7 +33,7 @@ public A runIdentity() { * {@inheritDoc} */ @Override - public Identity flatMap(Function>> f) { + public Identity flatMap(Fn1>> f) { return f.apply(runIdentity()).coerce(); } @@ -41,7 +41,7 @@ public Identity flatMap(Function Identity fmap(Function fn) { + public Identity fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -57,8 +57,8 @@ public Identity pure(B b) { * {@inheritDoc} */ @Override - public Identity zip(Applicative, Identity> appFn) { - return new Identity<>(appFn.>>coerce().runIdentity().apply(a)); + public Identity zip(Applicative, Identity> appFn) { + return new Identity<>(appFn.>>coerce().runIdentity().apply(a)); } /** @@ -66,7 +66,7 @@ public Identity zip(Applicative, Identit */ @Override public Lazy> lazyZip( - Lazy, Identity>> lazyAppFn) { + Lazy, Identity>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } @@ -93,8 +93,8 @@ public Identity discardR(Applicative> appB) { @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return (AppTrav) fn.apply(runIdentity()).fmap(Identity::new); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java index ea1bef9cd..c79a4c0c7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java @@ -2,17 +2,15 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.LinkedList; import java.util.Objects; -import java.util.function.Function; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.recurse; import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; @@ -39,10 +37,10 @@ private Lazy() { * {@inheritDoc} */ @Override - public Lazy flatMap(Function>> f) { + public Lazy flatMap(Fn1>> f) { @SuppressWarnings("unchecked") Lazy source = (Lazy) this; @SuppressWarnings({"unchecked", "RedundantCast"}) - Function> flatMap = (Function>) (Object) f; + Fn1> flatMap = (Fn1>) (Object) f; return new Compose<>(source, flatMap); } @@ -53,8 +51,8 @@ public Lazy flatMap(Function>> f) { @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Function fn, - Function pure) { + AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + Fn1 pure) { return fn.apply(value()).fmap(b -> (TravB) lazy(b)).coerce(); } @@ -70,7 +68,7 @@ public final Lazy pure(B b) { * {@inheritDoc} */ @Override - public final Lazy fmap(Function fn) { + public final Lazy fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -78,7 +76,7 @@ public final Lazy fmap(Function fn) { * {@inheritDoc} */ @Override - public Lazy zip(Applicative, Lazy> appFn) { + public Lazy zip(Applicative, Lazy> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -127,12 +125,12 @@ public static Lazy lazy(A value) { /** * Wrap a computation in a lazy computation. * - * @param supplier the computation - * @param the value type + * @param the value type + * @param fn0 the computation * @return the new {@link Lazy} */ - public static Lazy lazy(Supplier supplier) { - return new Later<>(fn0(supplier)); + public static Lazy lazy(Fn0 fn0) { + return new Later<>(fn0); } private static final class Later extends Lazy { @@ -149,18 +147,18 @@ public A value() { } private static final class Compose extends Lazy { - private final Lazy source; - private final Function> flatMap; + private final Lazy source; + private final Fn1> flatMap; private Compose(Lazy source, - Function> flatMap) { + Fn1> flatMap) { this.source = source; this.flatMap = flatMap; } @Override public A value() { - @SuppressWarnings("unchecked") Tuple2, LinkedList>>> tuple = + @SuppressWarnings("unchecked") Tuple2, LinkedList>>> tuple = tuple((Lazy) this, new LinkedList<>()); @SuppressWarnings("unchecked") A a = (A) trampoline(into((source, flatMaps) -> { diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java index efb2e0247..f1a4b3243 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java @@ -8,8 +8,6 @@ import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.optics.Prism; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; @@ -31,7 +29,7 @@ public final class Market implements private final Fn1 bt; private final Fn1> sta; - public Market(Function bt, Function> sta) { + public Market(Fn1 bt, Fn1> sta) { this.bt = fn1(bt); this.sta = fn1(sta); } @@ -39,7 +37,7 @@ public Market(Function bt, FunctionB -> T. * - * @return a {@link Function}<B, T> + * @return a {@link Fn1}<B, T> */ public Fn1 bt() { return bt; @@ -48,7 +46,7 @@ public Market(Function bt, FunctionS -> {@link Either}<T, A>. * - * @return a {@link Function}<S, {@link Either}<T, A>> + * @return a {@link Fn1}<S, {@link Either}<T, A>> */ public Fn1> sta() { return sta; @@ -66,7 +64,7 @@ public Market pure(U u) { * {@inheritDoc} */ @Override - public Market flatMap(Function>> f) { + public Market flatMap(Fn1>> f) { return new Market<>(b -> f.apply(bt().apply(b)).>coerce().bt().apply(b), s -> sta().apply(s).invert() .flatMap(t -> f.apply(t).>coerce().sta() @@ -77,8 +75,8 @@ public Market flatMap(Function Market zip(Applicative, Market> appFn) { - Market> marketF = appFn.coerce(); + public Market zip(Applicative, Market> appFn) { + Market> marketF = appFn.coerce(); return new Market<>(b -> marketF.bt().apply(b).apply(bt().apply(b)), s -> sta().apply(s).invert().zip(marketF.sta().apply(s).invert()).invert()); } @@ -87,8 +85,8 @@ public Market zip(Applicative, * {@inheritDoc} */ @Override - public Market fmap(Function fn) { - return diMapR(fn); + public Market fmap(Fn1 fn) { + return diMapR(fn::apply); } /** @@ -105,8 +103,8 @@ public Market, Choice2> cocartesian() { * {@inheritDoc} */ @Override - public Market diMap(Function lFn, - Function rFn) { + public Market diMap(Fn1 lFn, + Fn1 rFn) { return new Market<>(bt.fmap(rFn), sta.diMapL(lFn).diMapR(c -> c.biMapL(rFn))); } @@ -114,7 +112,7 @@ public Market diMap(Function lFn, * {@inheritDoc} */ @Override - public Market diMapL(Function fn) { + public Market diMapL(Fn1 fn) { return (Market) Cocartesian.super.diMapL(fn); } @@ -122,7 +120,7 @@ public Market diMapL(Function fn) { * {@inheritDoc} */ @Override - public Market diMapR(Function fn) { + public Market diMapR(Fn1 fn) { return (Market) Cocartesian.super.diMapR(fn); } @@ -130,7 +128,7 @@ public Market diMapR(Function fn) { * {@inheritDoc} */ @Override - public Market contraMap(Function fn) { + public Market contraMap(Fn1 fn) { return (Market) Cocartesian.super.contraMap(fn); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java index 68de3685d..ed3f17470 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java @@ -8,8 +8,6 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -89,7 +87,7 @@ public State withState(Fn1 fn) { * {@inheritDoc} */ @Override - public State flatMap(Function>> f) { + public State flatMap(Fn1>> f) { return state(s -> run(s).into((a, s2) -> f.apply(a).>coerce().run(s2))); } @@ -105,7 +103,7 @@ public State pure(B b) { * {@inheritDoc} */ @Override - public State fmap(Function fn) { + public State fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -113,7 +111,7 @@ public State fmap(Function fn) { * {@inheritDoc} */ @Override - public State zip(Applicative, State> appFn) { + public State zip(Applicative, State> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -122,7 +120,7 @@ public State zip(Applicative, State Lazy> lazyZip( - Lazy, State>> lazyAppFn) { + Lazy, State>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java index 3b2ea5e79..c601e6d65 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java @@ -1,12 +1,11 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cocartesian; import com.jnape.palatable.lambda.monad.Monad; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.choice.Choice2.b; /** @@ -36,7 +35,7 @@ public B unTagged() { * {@inheritDoc} */ @Override - public Tagged flatMap(Function>> f) { + public Tagged flatMap(Fn1>> f) { return f.apply(b).coerce(); } @@ -52,7 +51,7 @@ public Tagged pure(C c) { * {@inheritDoc} */ @Override - public Tagged fmap(Function fn) { + public Tagged fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -60,7 +59,7 @@ public Tagged fmap(Function fn) { * {@inheritDoc} */ @Override - public Tagged zip(Applicative, Tagged> appFn) { + public Tagged zip(Applicative, Tagged> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -92,8 +91,7 @@ public Tagged, Choice2> cocartesian() { * {@inheritDoc} */ @Override - public Tagged diMap(Function lFn, - Function rFn) { + public Tagged diMap(Fn1 lFn, Fn1 rFn) { return new Tagged<>(rFn.apply(b)); } @@ -101,7 +99,7 @@ public Tagged diMap(Function lFn, * {@inheritDoc} */ @Override - public Tagged diMapL(Function fn) { + public Tagged diMapL(Fn1 fn) { return (Tagged) Cocartesian.super.diMapL(fn); } @@ -109,7 +107,7 @@ public Tagged diMapL(Function fn) { * {@inheritDoc} */ @Override - public Tagged diMapR(Function fn) { + public Tagged diMapR(Fn1 fn) { return (Tagged) Cocartesian.super.diMapR(fn); } @@ -117,7 +115,7 @@ public Tagged diMapR(Function fn) { * {@inheritDoc} */ @Override - public Tagged contraMap(Function fn) { + public Tagged contraMap(Fn1 fn) { return (Tagged) Cocartesian.super.contraMap(fn); } } diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index d2e630e20..2848da1fc 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -5,6 +5,8 @@ import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -12,8 +14,8 @@ import java.util.LinkedList; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; -import java.util.function.Function; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.Fn0.fn0; @@ -77,7 +79,7 @@ public final CompletableFuture unsafePerformAsyncIO() { * @param recoveryFn the recovery function * @return the guarded {@link IO} */ - public final IO exceptionally(Function recoveryFn) { + public final IO exceptionally(Fn1 recoveryFn) { return new IO() { @Override public A unsafePerformIO() { @@ -103,7 +105,7 @@ public final IO pure(B b) { * {@inheritDoc} */ @Override - public final IO fmap(Function fn) { + public final IO fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -111,11 +113,11 @@ public final IO fmap(Function fn) { * {@inheritDoc} */ @Override - public final IO zip(Applicative, IO> appFn) { + public final IO zip(Applicative, IO> appFn) { @SuppressWarnings("unchecked") IO source = (IO) this; @SuppressWarnings("unchecked") - IO> zip = (IO>) (Object) appFn; + IO> zip = (IO>) (Object) appFn; return new Compose<>(source, a(zip)); } @@ -123,7 +125,7 @@ public final IO zip(Applicative, IO> * {@inheritDoc} */ @Override - public Lazy> lazyZip(Lazy, IO>> lazyAppFn) { + public Lazy> lazyZip(Lazy, IO>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } @@ -147,11 +149,11 @@ public final IO discardR(Applicative> appB) { * {@inheritDoc} */ @Override - public final IO flatMap(Function>> f) { + public final IO flatMap(Fn1>> f) { @SuppressWarnings("unchecked") IO source = (IO) this; @SuppressWarnings({"unchecked", "RedundantCast"}) - Function> flatMap = (Function>) (Object) f; + Fn1> flatMap = (Fn1>) (Object) f; return new Compose<>(source, Choice2.b(flatMap)); } @@ -187,7 +189,7 @@ public static IO io(Fn0 fn0) { return new IO() { @Override public A unsafePerformIO() { - return fn0.get(); + return fn0.apply(); } @Override @@ -198,13 +200,16 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { } /** - * Static factory method for creating an {@link IO} that runs runnable and returns {@link Unit}. + * Static factory method for creating an {@link IO} that runs a {@link SideEffect} and returns {@link Unit}. * - * @param runnable the {@link Runnable} + * @param sideEffect the {@link SideEffect} * @return the {@link IO} */ - public static IO io(Runnable runnable) { - return io(fn0(runnable)); + public static IO io(SideEffect sideEffect) { + return io(fn0(() -> { + sideEffect.Ω(); + return UNIT; + })); } /** @@ -228,17 +233,16 @@ public A unsafePerformIO() { @Override public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return supplier.get(); + return supplier.apply(); } }; } private static final class Compose extends IO { - private final IO source; - private final Choice2>, Function>> composition; + private final IO source; + private final Choice2>, Fn1>> composition; - private Compose(IO source, - Choice2>, Function>> composition) { + private Compose(IO source, Choice2>, Fn1>> composition) { this.source = source; this.composition = composition; } @@ -269,7 +273,8 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { CompletableFuture future = (CompletableFuture) deforest(new LinkedList<>()) .into((source, compositions) -> foldLeft( (io, composition) -> composition - .match(zip -> zip.unsafePerformAsyncIO(executor).thenCompose(io::thenApply), + .match(zip -> zip.unsafePerformAsyncIO(executor) + .thenCompose(f -> io.thenApply(f.toFunction())), flatMap -> io.thenComposeAsync(obj -> flatMap.apply(obj) .unsafePerformAsyncIO(executor))), source.unsafePerformAsyncIO(executor), @@ -277,9 +282,9 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { return future; } - private Tuple2, LinkedList>, Function>>>> - deforest(LinkedList>, Function>>> branches) { - Tuple2, LinkedList>, Function>>>> args = + private Tuple2, LinkedList>, Fn1>>>> + deforest(LinkedList>, Fn1>>> branches) { + Tuple2, LinkedList>, Fn1>>>> args = tuple(this, branches); return trampoline(into((source, compositions) -> { IO leaf = source.source; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java index d35d92c0b..5198f66f7 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java @@ -1,15 +1,16 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn0; + import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.Supplier; public final class ConsingIterator implements Iterator { - private final A head; - private final Supplier> asSupplier; - private Iterator asIterator; - private boolean iteratedHead; + private final A head; + private final Fn0> asSupplier; + private Iterator asIterator; + private boolean iteratedHead; public ConsingIterator(A head, Iterable as) { this.head = head; @@ -23,7 +24,7 @@ public boolean hasNext() { return true; if (asIterator == null) - asIterator = asSupplier.get(); + asIterator = asSupplier.apply(); return asIterator.hasNext(); } 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 1b9f315ff..7503e152a 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java @@ -1,19 +1,20 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn1; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.All.all; import static java.util.Collections.singletonList; public final class FilteringIterable implements Iterable { - private final List> predicates; - private final Iterable as; + private final List> predicates; + private final Iterable as; - public FilteringIterable(Function predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + public FilteringIterable(Fn1 predicate, Iterable as) { + List> predicates = new ArrayList<>(singletonList(predicate)); while (as instanceof FilteringIterable) { FilteringIterable nested = (FilteringIterable) as; predicates.addAll(0, nested.predicates); @@ -25,7 +26,7 @@ public FilteringIterable(Function predicate, Itera @Override public Iterator iterator() { - Function metaPredicate = a -> all(p -> p.apply(a), predicates); + Fn1 metaPredicate = a -> all(p -> p.apply(a), predicates); return new FilteringIterator<>(metaPredicate, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java index 5b9358c01..d283a1129 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java @@ -1,15 +1,16 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn1; + import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.Function; public final class FilteringIterator extends ImmutableIterator { - private final Function predicate; - private final RewindableIterator rewindableIterator; + private final Fn1 predicate; + private final RewindableIterator rewindableIterator; - public FilteringIterator(Function predicate, Iterator iterator) { + public FilteringIterator(Fn1 predicate, Iterator iterator) { this.predicate = predicate; rewindableIterator = new RewindableIterator<>(iterator); } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java b/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java index b65510f55..4bffb3b3d 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java @@ -1,20 +1,21 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn1; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; import static java.util.Collections.singletonList; public final class MappingIterable implements Iterable { - private final Iterable as; - private final List> mappers; + private final Iterable as; + private final List> mappers; @SuppressWarnings("unchecked") - public MappingIterable(Function fn, Iterable as) { - List> mappers = new ArrayList<>(singletonList(fn)); + public MappingIterable(Fn1 fn, Iterable as) { + List> mappers = new ArrayList<>(singletonList(fn)); while (as instanceof MappingIterable) { MappingIterable nested = (MappingIterable) as; as = (Iterable) nested.as; @@ -27,8 +28,8 @@ public MappingIterable(Function fn, Iterable as) { @Override @SuppressWarnings("unchecked") public Iterator iterator() { - Function fnComposedOnTheHeap = a -> foldLeft((x, fn) -> ((Function) fn).apply(x), - a, mappers); - return new MappingIterator<>((Function) fnComposedOnTheHeap, as.iterator()); + Fn1 fnComposedOnTheHeap = a -> foldLeft((x, fn) -> ((Fn1) fn).apply(x), + a, mappers); + return new MappingIterator<>((Fn1) fnComposedOnTheHeap, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java index 0d336fa89..ed13cf281 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java @@ -1,14 +1,15 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn1; + import java.util.Iterator; -import java.util.function.Function; public final class MappingIterator extends ImmutableIterator { - private final Function function; - private final Iterator iterator; + private final Fn1 function; + private final Iterator iterator; - public MappingIterator(Function function, Iterator iterator) { + public MappingIterator(Fn1 function, Iterator iterator) { this.function = function; this.iterator = iterator; } 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 bd3aa87b6..591e561f5 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java @@ -1,20 +1,20 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn1; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.Any.any; import static java.util.Collections.singletonList; public final class PredicatedDroppingIterable implements Iterable { - private final List> predicates; - private final Iterable as; - - public PredicatedDroppingIterable(Function predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + private final List> predicates; + private final Iterable as; + public PredicatedDroppingIterable(Fn1 predicate, Iterable as) { + List> predicates = new ArrayList<>(singletonList(predicate)); while (as instanceof PredicatedDroppingIterable) { PredicatedDroppingIterable nested = (PredicatedDroppingIterable) as; as = nested.as; @@ -26,7 +26,7 @@ public PredicatedDroppingIterable(Function predica @Override public Iterator iterator() { - Function metaPredicate = a -> any(p -> p.apply(a), predicates); + Fn1 metaPredicate = a -> any(p -> p.apply(a), predicates); return new PredicatedDroppingIterator<>(metaPredicate, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java index 7fe16c64b..8bbba7783 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java @@ -1,15 +1,16 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn1; + import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.Function; public final class PredicatedDroppingIterator extends ImmutableIterator { - private final Function predicate; - private final RewindableIterator rewindableIterator; - private boolean finishedDropping; + private final Fn1 predicate; + private final RewindableIterator rewindableIterator; + private boolean finishedDropping; - public PredicatedDroppingIterator(Function predicate, Iterator asIterator) { + public PredicatedDroppingIterator(Fn1 predicate, Iterator asIterator) { this.predicate = predicate; rewindableIterator = new RewindableIterator<>(asIterator); finishedDropping = false; 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 14201849d..8a612fa11 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java @@ -1,19 +1,20 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn1; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn2.All.all; import static java.util.Collections.singletonList; public final class PredicatedTakingIterable implements Iterable { - private final List> predicates; - private final Iterable as; + private final List> predicates; + private final Iterable as; - public PredicatedTakingIterable(Function predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + public PredicatedTakingIterable(Fn1 predicate, Iterable as) { + List> predicates = new ArrayList<>(singletonList(predicate)); while (as instanceof PredicatedTakingIterable) { PredicatedTakingIterable nested = (PredicatedTakingIterable) as; predicates.addAll(0, nested.predicates); @@ -25,7 +26,7 @@ public PredicatedTakingIterable(Function predicate @Override public Iterator iterator() { - Function metaPredicate = a -> all(p -> p.apply(a), predicates); + Fn1 metaPredicate = a -> all(p -> p.apply(a), predicates); return new PredicatedTakingIterator<>(metaPredicate, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java index 370ef1e84..6d228ae85 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java @@ -1,16 +1,16 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn1; + import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.Function; public final class PredicatedTakingIterator extends ImmutableIterator { - private final Function predicate; - private final RewindableIterator rewindableIterator; - private boolean stillTaking; + private final Fn1 predicate; + private final RewindableIterator rewindableIterator; + private boolean stillTaking; - public PredicatedTakingIterator(Function predicate, - Iterator asIterator) { + public PredicatedTakingIterator(Fn1 predicate, Iterator asIterator) { this.predicate = predicate; rewindableIterator = new RewindableIterator<>(asIterator); stillTaking = true; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java index 27427b2cb..63bb5611f 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.iteration; import com.jnape.palatable.lambda.adt.hlist.Tuple3; +import com.jnape.palatable.lambda.functions.Fn0; import java.time.Duration; import java.time.Instant; @@ -10,11 +11,11 @@ import java.util.function.Supplier; public final class RateLimitingIterable implements Iterable { - private final Iterable as; - private final Set>> rateLimits; + private final Iterable as; + private final Set>> rateLimits; - public RateLimitingIterable(Iterable as, Set>> rateLimits) { - Set>> combinedRateLimits = new HashSet<>(rateLimits); + public RateLimitingIterable(Iterable as, Set>> rateLimits) { + Set>> combinedRateLimits = new HashSet<>(rateLimits); if (as instanceof RateLimitingIterable) { RateLimitingIterable inner = (RateLimitingIterable) as; combinedRateLimits.addAll(inner.rateLimits); diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java index 510c95d91..057106dd9 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.adt.hlist.Tuple3; +import com.jnape.palatable.lambda.functions.Fn0; import java.time.Duration; import java.time.Instant; @@ -12,7 +13,6 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.adt.Try.failure; import static com.jnape.palatable.lambda.adt.Try.trying; @@ -27,11 +27,11 @@ import static java.util.Collections.emptyList; public final class RateLimitingIterator implements Iterator { - private final Iterator asIterator; - private final Set>> rateLimits; - private final Map>, List> timeSlicesByRateLimit; + private final Iterator asIterator; + private final Set>> rateLimits; + private final Map>, List> timeSlicesByRateLimit; - public RateLimitingIterator(Iterator asIterator, Set>> rateLimits) { + public RateLimitingIterator(Iterator asIterator, Set>> rateLimits) { this.asIterator = asIterator; this.rateLimits = rateLimits; timeSlicesByRateLimit = new HashMap<>(); @@ -54,12 +54,12 @@ private void awaitNextTimeSlice() { rateLimits.forEach(rateLimit -> { awaitNextTimeSliceForRateLimit(rateLimit); List timeSlicesForRateLimit = timeSlicesByRateLimit.getOrDefault(rateLimit, new ArrayList<>()); - timeSlicesForRateLimit.add(rateLimit._3().get()); + timeSlicesForRateLimit.add(rateLimit._3().apply()); timeSlicesByRateLimit.put(rateLimit, timeSlicesForRateLimit); }); } - private void awaitNextTimeSliceForRateLimit(Tuple3> rateLimit) { + private void awaitNextTimeSliceForRateLimit(Tuple3> rateLimit) { while (rateLimitExhaustedInTimeSlice(rateLimit)) { join(trying(() -> sleep(0)) .fmap(Try::success) @@ -68,12 +68,12 @@ private void awaitNextTimeSliceForRateLimit(Tuple3> rateLimit) { + private boolean rateLimitExhaustedInTimeSlice(Tuple3> rateLimit) { List timeSlicesForRateLimit = timeSlicesByRateLimit.getOrDefault(rateLimit, emptyList()); return rateLimit.into((limit, duration, instantSupplier) -> { - Instant timeSliceEnd = instantSupplier.get(); + Instant timeSliceEnd = instantSupplier.apply(); Instant previousTimeSliceEnd = timeSliceEnd.minus(duration); - timeSlicesForRateLimit.removeIf(lt(previousTimeSliceEnd)); + timeSlicesForRateLimit.removeIf(lt(previousTimeSliceEnd).toPredicate()); return max(0L, limit - size(filter(mark -> lte(mark, previousTimeSliceEnd) && gte(mark, timeSliceEnd), timeSlicesForRateLimit))) == 0; }); } diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java index d195b14b3..187982cca 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java @@ -1,16 +1,17 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn2; + import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.function.BiFunction; public final class ScanningIterator extends ImmutableIterator { - private final BiFunction scanner; - private final Iterator asIterator; - private B b; + private final Fn2 scanner; + private final Iterator asIterator; + private B b; - public ScanningIterator(BiFunction scanner, B b, + public ScanningIterator(Fn2 scanner, B b, Iterator asIterator) { this.scanner = scanner; this.b = b; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java index 0d014df81..146b19126 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java @@ -2,18 +2,18 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import java.util.NoSuchElementException; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; public final class UnfoldingIterator extends ImmutableIterator { - private final Function>> function; - private B seed; - private Maybe> maybeAcc; + private final Fn1>> function; + private B seed; + private Maybe> maybeAcc; - public UnfoldingIterator(Function>> function, B seed) { + public UnfoldingIterator(Fn1>> function, B seed) { this.function = function; this.seed = seed; } @@ -31,8 +31,8 @@ public A next() { if (!hasNext()) throw new NoSuchElementException(); - Tuple2 acc = maybeAcc.orElseThrow(NoSuchElementException::new); - A next = acc._1(); + Tuple2 acc = maybeAcc.orElseThrow(NoSuchElementException::new); + A next = acc._1(); seed = acc._2(); maybeAcc = null; return next; diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java b/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java index 1b0909fd4..20175de5c 100644 --- a/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java @@ -1,14 +1,15 @@ package com.jnape.palatable.lambda.iteration; +import com.jnape.palatable.lambda.functions.Fn2; + import java.util.Iterator; -import java.util.function.BiFunction; public final class ZippingIterator extends ImmutableIterator { - private final BiFunction zipper; - private final Iterator asIterator; - private final Iterator bsIterator; + private final Fn2 zipper; + private final Iterator asIterator; + private final Iterator bsIterator; - public ZippingIterator(BiFunction zipper, Iterator asIterator, + public ZippingIterator(Fn2 zipper, Iterator asIterator, Iterator bsIterator) { this.asIterator = asIterator; this.bsIterator = bsIterator; diff --git a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java index 00aca101c..769218304 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java @@ -1,17 +1,16 @@ package com.jnape.palatable.lambda.monad; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn1.Id; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; /** * Monads are {@link Applicative} functors that support a flattening operation to unwrap M<M<A>> * -> M<A>. This flattening operation, coupled with {@link Applicative#zip(Applicative)}, gives rise to - * {@link Monad#flatMap(Function)}, a binding operation that maps the carrier value to a new monad instance in the same + * {@link Monad#flatMap(Fn1)}, a binding operation that maps the carrier value to a new monad instance in the same * category, and then unwraps the outer layer. *

* In addition to the applicative laws, there are 3 specific monad laws that monads should obey: @@ -36,7 +35,7 @@ public interface Monad> extends Applicative { * @param the resulting monad parameter type * @return the new monad instance */ - Monad flatMap(Function> f); + Monad flatMap(Fn1> f); /** * {@inheritDoc} @@ -48,16 +47,16 @@ public interface Monad> extends Applicative { * {@inheritDoc} */ @Override - default Monad fmap(Function fn) { - return flatMap(fn.andThen(this::pure)); + default Monad fmap(Fn1 fn) { + return flatMap(fn.fmap(this::pure)); } /** * {@inheritDoc} */ @Override - default Monad zip(Applicative, M> appFn) { - return appFn., M>>coerce().flatMap(this::fmap); + default Monad zip(Applicative, M> appFn) { + return appFn., M>>coerce().flatMap(this::fmap); } /** @@ -65,7 +64,7 @@ default Monad zip(Applicative, M> app */ @Override default Lazy> lazyZip( - Lazy, M>> lazyAppFn) { + Lazy, M>> lazyAppFn) { return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); } @@ -86,7 +85,7 @@ default Monad discardR(Applicative appB) { } /** - * Convenience static method equivalent to {@link Monad#flatMap(Function) flatMap}{@link Id#id() (id())}; + * Convenience static method equivalent to {@link Monad#flatMap(Fn1) flatMap}{@link Id#id() (id())}; * * @param mma the outer monad * @param the monad type diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java index 1afb4d426..e95bdd68d 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.monad.transformer; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -14,9 +15,9 @@ * {@link Applicative applicatives} can be composed in general, the same is not true in general of any two * {@link Monad monads}. However, there exist {@link Monad monads} that do compose, in general, with any other * {@link Monad}, provided that they are embedded inside the other {@link Monad}. When this is the case, they can offer - * implementations of {@link Monad#pure pure} and {@link Monad#flatMap(Function) flatMap} for free, simply by relying + * implementations of {@link Monad#pure pure} and {@link Monad#flatMap(Fn1) flatMap} for free, simply by relying * on the outer {@link Monad monad's} implementation of both, as well as their own privileged knowledge about how to - * merge the nested {@link Monad#flatMap(Function) flatMap} call. + * merge the nested {@link Monad#flatMap(Fn1) flatMap} call. *

* The term "monad transformer" describes a particular encoding of monadic composition. Because this general composition * of a particular {@link Monad} with any other {@link Monad} relies on privileged knowledge about the embedded @@ -51,7 +52,7 @@ public interface MonadT, G extends Monad, A> * {@inheritDoc} */ @Override - MonadT flatMap(Function>> f); + MonadT flatMap(Fn1>> f); /** * {@inheritDoc} @@ -63,7 +64,7 @@ public interface MonadT, G extends Monad, A> * {@inheritDoc} */ @Override - default MonadT fmap(Function fn) { + default MonadT fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -71,7 +72,7 @@ default MonadT fmap(Function fn) { * {@inheritDoc} */ @Override - default MonadT zip(Applicative, MonadT> appFn) { + default MonadT zip(Applicative, MonadT> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -80,7 +81,7 @@ default MonadT zip(Applicative, Mo */ @Override default Lazy> lazyZip( - Lazy, MonadT>> lazyAppFn) { + Lazy, MonadT>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java index 3b23327d9..d8a139f39 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -8,7 +9,6 @@ import com.jnape.palatable.lambda.monad.transformer.MonadT; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; @@ -40,7 +40,7 @@ private EitherT(Monad, M> melr) { * {@inheritDoc} */ @Override - public EitherT flatMap(Function, ?>>> f) { + public EitherT flatMap(Fn1, ?>>> f) { return eitherT(melr.flatMap(lr -> lr.match(l -> melr.pure(left(l)), r -> f.apply(r).>coerce().run()))); } @@ -57,7 +57,7 @@ public EitherT pure(R2 r2) { * {@inheritDoc} */ @Override - public EitherT fmap(Function fn) { + public EitherT fmap(Fn1 fn) { return MonadT.super.fmap(fn).coerce(); } @@ -66,7 +66,7 @@ public EitherT fmap(Function fn) { */ @Override public EitherT zip( - Applicative, MonadT, ?>> appFn) { + Applicative, MonadT, ?>> appFn) { return MonadT.super.zip(appFn).coerce(); } @@ -75,12 +75,12 @@ public EitherT zip( */ @Override public Lazy> lazyZip( - Lazy, MonadT, ?>>> lazyAppFn) { + Lazy, MonadT, ?>>> lazyAppFn) { return new Compose<>(melr) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( - maybeT.>>coerce() - .>, - Monad>, M>>run()))) + maybeT.>>coerce() + .>, + Monad>, M>>run()))) .fmap(compose -> eitherT(compose.getCompose())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java index 932680c8b..26ffffb51 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Identity; @@ -36,7 +37,7 @@ public >, FGA extends Monad> FGA run() { * {@inheritDoc} */ @Override - public IdentityT flatMap(Function, ?>>> f) { + public IdentityT flatMap(Fn1, ?>>> f) { return identityT(mia.flatMap(identityA -> f.apply(identityA.runIdentity()).>coerce().run())); } @@ -52,7 +53,7 @@ public IdentityT pure(B b) { * {@inheritDoc} */ @Override - public IdentityT fmap(Function fn) { + public IdentityT fmap(Fn1 fn) { return MonadT.super.fmap(fn).coerce(); } @@ -60,7 +61,7 @@ public IdentityT fmap(Function fn) { * {@inheritDoc} */ @Override - public IdentityT zip(Applicative, MonadT, ?>> appFn) { + public IdentityT zip(Applicative, MonadT, ?>> appFn) { return MonadT.super.zip(appFn).coerce(); } @@ -69,12 +70,12 @@ public IdentityT zip(Applicative, Mon */ @Override public Lazy> lazyZip( - Lazy, MonadT, ?>>> lazyAppFn) { + Lazy, MonadT, ?>>> lazyAppFn) { return new Compose<>(mia) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( - maybeT.>>coerce() - .>, - Monad>, M>>run()))) + maybeT.>>coerce() + .>, + Monad>, M>>run()))) .fmap(compose -> identityT(compose.getCompose())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java index fe10e8142..d35ddc215 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Compose; @@ -8,12 +9,11 @@ import com.jnape.palatable.lambda.monad.transformer.MonadT; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** - * A {@link MonadT monad transformer} for {@link Lazy}. Note that {@link LazyT#flatMap(Function)} must force its value. + * A {@link MonadT monad transformer} for {@link Lazy}. Note that {@link LazyT#flatMap(Fn1)} must force its value. * * @param the outer {@link Monad} * @param the carrier type @@ -38,7 +38,7 @@ public >, FGA extends Monad> FGA run() { * {@inheritDoc} */ @Override - public LazyT flatMap(Function, ?>>> f) { + public LazyT flatMap(Fn1, ?>>> f) { return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value())., B>>coerce().run())); } @@ -54,7 +54,7 @@ public LazyT pure(B b) { * {@inheritDoc} */ @Override - public LazyT fmap(Function fn) { + public LazyT fmap(Fn1 fn) { return MonadT.super.fmap(fn).coerce(); } @@ -62,7 +62,7 @@ public LazyT fmap(Function fn) { * {@inheritDoc} */ @Override - public LazyT zip(Applicative, MonadT, ?>> appFn) { + public LazyT zip(Applicative, MonadT, ?>> appFn) { return MonadT.super.zip(appFn).coerce(); } @@ -71,12 +71,12 @@ public LazyT zip(Applicative, MonadT< */ @Override public Lazy> lazyZip( - Lazy, MonadT, ?>>> lazyAppFn) { + Lazy, MonadT, ?>>> lazyAppFn) { return new Compose<>(mla) .lazyZip(lazyAppFn.fmap(lazyT -> new Compose<>( - lazyT.>>coerce() - .>, - Monad>, M>>run()))) + lazyT.>>coerce() + .>, + Monad>, M>>run()))) .fmap(compose -> lazyT(compose.getCompose())); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index f7d72406a..7f1cf151f 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -8,7 +9,6 @@ import com.jnape.palatable.lambda.monad.transformer.MonadT; import java.util.Objects; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; @@ -40,7 +40,7 @@ public >, FGA extends Monad> FGA run() { * {@inheritDoc} */ @Override - public MaybeT fmap(Function fn) { + public MaybeT fmap(Fn1 fn) { return MonadT.super.fmap(fn).coerce(); } @@ -56,7 +56,7 @@ public MaybeT pure(B b) { * {@inheritDoc} */ @Override - public MaybeT zip(Applicative, MonadT, ?>> appFn) { + public MaybeT zip(Applicative, MonadT, ?>> appFn) { return MonadT.super.zip(appFn).coerce(); } @@ -65,10 +65,11 @@ public MaybeT zip(Applicative, MonadT */ @Override public Lazy> lazyZip( - Lazy, MonadT, ?>>> lazyAppFn) { + Lazy, MonadT, ?>>> lazyAppFn) { return new Compose<>(mma) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( - maybeT.>>coerce().>, Monad>, M>>run()))) + maybeT.>>coerce() + .>, Monad>, M>>run()))) .fmap(compose -> maybeT(compose.getCompose())); } @@ -76,7 +77,7 @@ public Lazy> lazyZip( * {@inheritDoc} */ @Override - public MaybeT flatMap(Function, ?>>> f) { + public MaybeT flatMap(Fn1, ?>>> f) { return maybeT(mma.flatMap(ma -> ma .match(constantly(mma.pure(nothing())), a -> f.apply(a).>coerce().run()))); diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java index 3ff2d3e0b..8ecf83775 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java @@ -1,5 +1,7 @@ package com.jnape.palatable.lambda.monoid; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Map; import com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft; import com.jnape.palatable.lambda.functions.builtin.fn2.ReduceRight; @@ -7,9 +9,6 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.semigroup.Semigroup; -import java.util.function.Function; -import java.util.function.Supplier; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn1.Reverse.reverse; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; @@ -59,15 +58,15 @@ default A reduceRight(Iterable as) { * Iterable<A> (that is, an Iterable of elements this monoid is formed over), then * reduce the result from left to right. Under algebraic data types, this is isomorphic to a flatMap. * + * @param the input Iterable element type * @param fn the mapping function from A to B * @param bs the Iterable of Bs - * @param the input Iterable element type * @return the folded result under this Monoid * @see Map * @see Monoid#reduceLeft(Iterable) */ - default A foldMap(Function fn, Iterable bs) { - return FoldLeft.foldLeft(this.toBiFunction(), identity(), map(fn, bs)); + default A foldMap(Fn1 fn, Iterable bs) { + return FoldLeft.foldLeft(this, identity(), map(fn, bs)); } /** @@ -116,11 +115,11 @@ public A checkedApply(A x, A y) { }; } - static Monoid monoid(Semigroup semigroup, Supplier identitySupplier) { + static Monoid monoid(Semigroup semigroup, Fn0 identityFn0) { return new Monoid() { @Override public A identity() { - return identitySupplier.get(); + return identityFn0.apply(); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java index 383116e6d..219763fd3 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/AddAll.java @@ -1,13 +1,12 @@ package com.jnape.palatable.lambda.monoid.builtin; +import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; import com.jnape.palatable.lambda.monoid.Monoid; import java.util.Collection; -import java.util.function.Function; -import java.util.function.Supplier; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; @@ -19,7 +18,7 @@ * * @see Monoid */ -public final class AddAll> implements MonoidFactory, C> { +public final class AddAll> implements MonoidFactory, C> { private static final AddAll INSTANCE = new AddAll<>(); @@ -27,11 +26,11 @@ private AddAll() { } @Override - public Monoid checkedApply(Supplier cSupplier) { + public Monoid checkedApply(Fn0 cFn0) { return new Monoid() { @Override public C identity() { - return cSupplier.get(); + return cFn0.apply(); } @Override @@ -43,7 +42,7 @@ public C checkedApply(C xs, C ys) { } @Override - public C foldMap(Function fn, Iterable bs) { + public C foldMap(Fn1 fn, Iterable bs) { return FoldLeft.foldLeft((x, y) -> { x.addAll(y); return x; @@ -57,15 +56,15 @@ public static > AddAll addAll() { return (AddAll) INSTANCE; } - public static > Monoid addAll(Supplier collectionSupplier) { - return AddAll.addAll().apply(collectionSupplier); + public static > Monoid addAll(Fn0 collectionFn0) { + return AddAll.addAll().apply(collectionFn0); } - public static > Fn1 addAll(Supplier collectionSupplier, C xs) { - return addAll(collectionSupplier).apply(xs); + public static > Fn1 addAll(Fn0 collectionFn0, C xs) { + return addAll(collectionFn0).apply(xs); } - public static > C addAll(Supplier collectionSupplier, C xs, C ys) { - return addAll(collectionSupplier, xs).apply(ys); + public static > C addAll(Fn0 collectionFn0, C xs, C ys) { + return addAll(collectionFn0, xs).apply(ys); } } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java index e47e67df4..2ce32994c 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/And.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.monoid.Monoid; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Not.not; import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find; @@ -34,15 +32,10 @@ public Boolean checkedApply(Boolean x, Boolean y) { } @Override - public Boolean foldMap(Function fn, Iterable bs) { + public Boolean foldMap(Fn1 fn, Iterable bs) { return find(not(fn), bs).fmap(constantly(false)).orElse(true); } - @Override - public boolean test(Boolean x, Boolean y) { - return apply(x, y); - } - @Override public And flip() { return this; diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java index f9c53ed27..dbffbe748 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Compose.java @@ -6,8 +6,8 @@ import com.jnape.palatable.lambda.semigroup.Semigroup; import java.util.concurrent.CompletableFuture; -import java.util.function.Supplier; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.monoid.Monoid.monoid; import static java.util.concurrent.CompletableFuture.completedFuture; @@ -32,7 +32,7 @@ private Compose() { @Override public Monoid> checkedApply(Monoid aMonoid) { return monoid(com.jnape.palatable.lambda.semigroup.builtin.Compose.compose(aMonoid), - (Supplier>) () -> completedFuture(aMonoid.identity())); + fn0(() -> completedFuture(aMonoid.identity()))); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java index c02c09586..002834bd1 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java @@ -5,7 +5,6 @@ import com.jnape.palatable.lambda.monoid.Monoid; import java.util.Collections; -import java.util.function.Function; import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; @@ -33,7 +32,7 @@ public Iterable checkedApply(Iterable xs, Iterable ys) { } @Override - public Iterable foldMap(Function> fn, Iterable bs) { + public Iterable foldMap(Fn1> fn, Iterable bs) { return flatten(map(fn, bs)); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java index 69b1e356c..9c44abca9 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/First.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.monoid.Monoid; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.CatMaybes.catMaybes; import static com.jnape.palatable.lambda.functions.builtin.fn1.Head.head; @@ -39,7 +37,7 @@ public Maybe checkedApply(Maybe x, Maybe y) { } @Override - public Maybe foldMap(Function> fn, Iterable bs) { + public Maybe foldMap(Fn1> fn, Iterable bs) { return head(catMaybes(map(fn, bs))); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java index 9f594df75..0f5c5fcc9 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeMaps.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.monoid.builtin; +import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.BiMonoidFactory; import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; @@ -8,7 +9,6 @@ import java.util.Map; import java.util.function.BiFunction; -import java.util.function.Supplier; /** * A {@link Monoid} instance formed by {@link java.util.Map#merge(Object, Object, BiFunction)} and a semigroup over @@ -19,7 +19,7 @@ * @see Monoid * @see java.util.Map */ -public final class MergeMaps implements BiMonoidFactory>, Semigroup, Map> { +public final class MergeMaps implements BiMonoidFactory>, Semigroup, Map> { private static final MergeMaps INSTANCE = new MergeMaps<>(); @@ -27,13 +27,13 @@ private MergeMaps() { } @Override - public Monoid> checkedApply(Supplier> mSupplier, Semigroup semigroup) { + public Monoid> checkedApply(Fn0> mFn0, Semigroup semigroup) { return Monoid.>monoid((x, y) -> { - Map copy = mSupplier.get(); + Map copy = mFn0.apply(); copy.putAll(x); y.forEach((k, v) -> copy.merge(k, v, semigroup.toBiFunction())); return copy; - }, mSupplier); + }, mFn0); } @SuppressWarnings("unchecked") @@ -41,21 +41,21 @@ public static MergeMaps mergeMaps() { return (MergeMaps) INSTANCE; } - public static MonoidFactory, Map> mergeMaps(Supplier> mSupplier) { - return MergeMaps.mergeMaps().apply(mSupplier); + public static MonoidFactory, Map> mergeMaps(Fn0> mFn0) { + return MergeMaps.mergeMaps().apply(mFn0); } - public static Monoid> mergeMaps(Supplier> mSupplier, Semigroup semigroup) { - return mergeMaps(mSupplier).apply(semigroup); + public static Monoid> mergeMaps(Fn0> mFn0, Semigroup semigroup) { + return mergeMaps(mFn0).apply(semigroup); } - public static Fn1, Map> mergeMaps(Supplier> mSupplier, Semigroup semigroup, + public static Fn1, Map> mergeMaps(Fn0> mFn0, Semigroup semigroup, Map x) { - return mergeMaps(mSupplier, semigroup).apply(x); + return mergeMaps(mFn0, semigroup).apply(x); } - public static Map mergeMaps(Supplier> mSupplier, Semigroup semigroup, Map x, + public static Map mergeMaps(Fn0> mFn0, Semigroup semigroup, Map x, Map y) { - return mergeMaps(mSupplier, semigroup, x).apply(y); + return mergeMaps(mFn0, semigroup, x).apply(y); } } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java index 90e57807d..84c45f5f4 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Or.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.monoid.Monoid; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Find.find; @@ -33,12 +31,7 @@ public Boolean checkedApply(Boolean x, Boolean y) { } @Override - public boolean test(Boolean x, Boolean y) { - return apply(x, y); - } - - @Override - public Boolean foldMap(Function fn, Iterable bs) { + public Boolean foldMap(Fn1 fn, Iterable bs) { return find(fn, bs).fmap(constantly(true)).orElse(false); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java index 4e17c6e97..8ed724ad6 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Xor.java @@ -30,11 +30,6 @@ public Boolean checkedApply(Boolean x, Boolean y) { return x ^ y; } - @Override - public boolean test(Boolean x, Boolean y) { - return apply(x, y); - } - @Override public Xor flip() { return this; diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java index bcb0775d5..11fdd4345 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -13,8 +13,6 @@ import com.jnape.palatable.lambda.optics.functions.Set; import com.jnape.palatable.lambda.optics.functions.View; -import java.util.function.Function; - import static com.jnape.palatable.lambda.functions.Fn1.fn1; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -97,7 +95,7 @@ default Iso mirror() { * {@inheritDoc} */ @Override - default Iso fmap(Function fn) { + default Iso fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -113,7 +111,7 @@ default Iso pure(U u) { * {@inheritDoc} */ @Override - default Iso zip(Applicative, Iso> appFn) { + default Iso zip(Applicative, Iso> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -137,13 +135,13 @@ default Iso discardR(Applicative> appB) { * {@inheritDoc} */ @Override - default Iso flatMap(Function>> fn) { + default Iso flatMap(Fn1>> fn) { //noinspection RedundantTypeArguments return unIso().fmap(bt -> Fn2.fn2( - fn1(bt.andThen(fn.>andThen(Monad>::coerce)) - .andThen(Iso::unIso) - .andThen(Tuple2::_2) - .andThen(Fn1::fn1)))) + fn1(bt.fmap(fn.>fmap(Monad>::coerce)) + .fmap(Iso::unIso) + .fmap(Tuple2::_2) + .fmap(Fn1::fn1)))) .fmap(Fn2::uncurry) .fmap(bbu -> bbu.diMapL(Tuple2::fill)) .into(Iso::iso); @@ -153,7 +151,7 @@ default Iso flatMap(Function Iso diMapL(Function fn) { + default Iso diMapL(Fn1 fn) { return (Iso) Profunctor.super.diMapL(fn); } @@ -161,7 +159,7 @@ default Iso diMapL(Function fn) { * {@inheritDoc} */ @Override - default Iso diMapR(Function fn) { + default Iso diMapR(Fn1 fn) { return (Iso) Profunctor.super.diMapR(fn); } @@ -169,8 +167,8 @@ default Iso diMapR(Function fn) { * {@inheritDoc} */ @Override - default Iso diMap(Function lFn, - Function rFn) { + default Iso diMap(Fn1 lFn, + Fn1 rFn) { return this.mapS(lFn).mapT(rFn); } @@ -178,7 +176,7 @@ default Iso diMap(Function lFn, * {@inheritDoc} */ @Override - default Iso contraMap(Function fn) { + default Iso contraMap(Fn1 fn) { return (Iso) Profunctor.super.contraMap(fn); } @@ -186,7 +184,7 @@ default Iso contraMap(Function fn) { * {@inheritDoc} */ @Override - default Iso mapS(Function fn) { + default Iso mapS(Fn1 fn) { return iso(Optic.super.mapS(fn)); } @@ -194,7 +192,7 @@ default Iso mapS(Function fn) { * {@inheritDoc} */ @Override - default Iso mapT(Function fn) { + default Iso mapT(Fn1 fn) { return iso(Optic.super.mapT(fn)); } @@ -202,7 +200,7 @@ default Iso mapT(Function fn) { * {@inheritDoc} */ @Override - default Iso mapA(Function fn) { + default Iso mapA(Fn1 fn) { return iso(Optic.super.mapA(fn)); } @@ -210,7 +208,7 @@ default Iso mapA(Function fn) { * {@inheritDoc} */ @Override - default Iso mapB(Function fn) { + default Iso mapB(Fn1 fn) { return iso(Optic.super.mapB(fn)); } @@ -241,8 +239,7 @@ default Iso compose(Optic, ? supe * @param the smaller type for mirrored focusing * @return the iso */ - static Iso iso(Function f, - Function g) { + static Iso iso(Fn1 f, Fn1 g) { return iso(optic(pafb -> pafb.diMap(f, fb -> fb.fmap(g)))); } @@ -278,7 +275,7 @@ static Iso iso( * @param the other side of the isomorphism * @return the simple iso */ - static Iso.Simple simpleIso(Function f, Function g) { + static Iso.Simple simpleIso(Fn1 f, Fn1 g) { return adapt(iso(f, g)); } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java index 8b5746c75..48e16495c 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java @@ -2,15 +2,13 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Both; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.monad.Monad; -import java.util.function.BiFunction; -import java.util.function.Function; - import static com.jnape.palatable.lambda.optics.Iso.iso; import static com.jnape.palatable.lambda.optics.Lens.Simple.adapt; import static com.jnape.palatable.lambda.optics.functions.Set.set; @@ -148,7 +146,7 @@ public interface Lens extends * {@inheritDoc} */ @Override - default Lens fmap(Function fn) { + default Lens fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -164,7 +162,7 @@ default Lens pure(U u) { * {@inheritDoc} */ @Override - default Lens zip(Applicative, Lens> appFn) { + default Lens zip(Applicative, Lens> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -188,7 +186,7 @@ default Lens discardR(Applicative> appB) { * {@inheritDoc} */ @Override - default Lens flatMap(Function>> f) { + default Lens flatMap(Fn1>> f) { return lens(view(this), (s, b) -> set(f.apply(set(this, b, s)).>coerce(), b, s)); } @@ -197,7 +195,7 @@ default Lens flatMap(Function Lens diMapL(Function fn) { + default Lens diMapL(Fn1 fn) { return (Lens) Profunctor.super.diMapL(fn); } @@ -205,7 +203,7 @@ default Lens diMapL(Function fn) { * {@inheritDoc} */ @Override - default Lens diMapR(Function fn) { + default Lens diMapR(Fn1 fn) { return (Lens) Profunctor.super.diMapR(fn); } @@ -213,8 +211,7 @@ default Lens diMapR(Function fn) { * {@inheritDoc} */ @Override - default Lens diMap(Function lFn, - Function rFn) { + default Lens diMap(Fn1 lFn, Fn1 rFn) { return this.mapS(lFn).mapT(rFn); } @@ -222,7 +219,7 @@ default Lens diMap(Function lFn, * {@inheritDoc} */ @Override - default Lens contraMap(Function fn) { + default Lens contraMap(Fn1 fn) { return (Lens) Profunctor.super.contraMap(fn); } @@ -230,7 +227,7 @@ default Lens contraMap(Function fn) { * {@inheritDoc} */ @Override - default Lens mapS(Function fn) { + default Lens mapS(Fn1 fn) { return lens(Optic.super.mapS(fn)); } @@ -238,7 +235,7 @@ default Lens mapS(Function fn) { * {@inheritDoc} */ @Override - default Lens mapT(Function fn) { + default Lens mapT(Fn1 fn) { return lens(Optic.super.mapT(fn)); } @@ -246,7 +243,7 @@ default Lens mapT(Function fn) { * {@inheritDoc} */ @Override - default Lens mapA(Function fn) { + default Lens mapA(Fn1 fn) { return lens(Optic.super.mapA(fn)); } @@ -254,7 +251,7 @@ default Lens mapA(Function fn) { * {@inheritDoc} */ @Override - default Lens mapB(Function fn) { + default Lens mapB(Fn1 fn) { return lens(Optic.super.mapB(fn)); } @@ -295,8 +292,8 @@ default Lens compose(Optic, ? super Functor * @param the type of the "smaller" update value * @return the lens */ - static Lens lens(Function getter, - BiFunction setter) { + static Lens lens(Fn1 getter, + Fn2 setter) { return lens(Optic., Functor, S, T, A, B, Functor>, @@ -337,8 +334,8 @@ static Lens lens(Optic, ? super Funct * @param the type of both "smaller" values * @return the lens */ - static Lens.Simple simpleLens(Function getter, - BiFunction setter) { + static Lens.Simple simpleLens(Fn1 getter, + Fn2 setter) { return adapt(lens(getter, setter)); } @@ -356,7 +353,7 @@ static Lens.Simple simpleLens(Function gett * @return the dual-focus lens */ static Lens, Tuple2> both(Lens f, Lens g) { - return lens(Both.both(view(f), view(g)), (s, cd) -> cd.biMap(set(f), set(g)).into(Fn1::compose).apply(s)); + return lens(Both.both(view(f), view(g)), (s, cd) -> cd.biMap(set(f), set(g)).into(Fn1::contraMap).apply(s)); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java index 4eeac4f75..be518ad7a 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java @@ -4,8 +4,6 @@ import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; -import java.util.function.Function; - /** * A generic supertype representation for profunctor optics. *

@@ -107,7 +105,7 @@ PRFU apply(PAFB pafb) { * @param the new left side of the output profunctor * @return the new optic */ - default Optic mapS(Function fn) { + default Optic mapS(Fn1 fn) { return optic(pafb -> { Profunctor, ? extends P> psft = apply(pafb); return psft.diMapL(fn); @@ -121,7 +119,7 @@ default Optic mapS(Function fn) { * @param the new right side's functor embedding of the output profunctor * @return the new optic */ - default Optic mapT(Function fn) { + default Optic mapT(Fn1 fn) { return optic(pafb -> { Profunctor, ? extends P> psft = apply(pafb); return psft.diMapR(ft -> ft.fmap(fn)); @@ -135,7 +133,7 @@ default Optic mapT(Function fn) { * @param the new left side of the input profunctor * @return the new optic */ - default Optic mapA(Function fn) { + default Optic mapA(Fn1 fn) { return optic(pcfb -> { @SuppressWarnings("UnnecessaryLocalVariable") Profunctor, ? extends P> psft = apply(pcfb.diMapL(fn)); @@ -146,11 +144,11 @@ default Optic mapA(Function fn) { /** * Contravariantly map B to Z, yielding a new optic. * - * @param fn the mapping function * @param the new right side's functor embedding of the input profunctor + * @param fn the mapping function * @return the new optic */ - default Optic mapB(Function fn) { + default Optic mapB(Fn1 fn) { return optic(pafz -> apply(pafz.diMapR(fz -> fz.fmap(fn)))); } @@ -176,8 +174,7 @@ default Optic mapB(Function fn) { FB extends Functor, FT extends Functor, PAFB extends Profunctor, - PSFT extends Profunctor> Optic optic( - Function fn) { + PSFT extends Profunctor> Optic optic(Fn1 fn) { return new Optic() { @Override @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java index bf2afb487..b52f67fd0 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Cocartesian; import com.jnape.palatable.lambda.functor.Functor; @@ -16,8 +17,6 @@ import com.jnape.palatable.lambda.optics.functions.Re; import com.jnape.palatable.lambda.optics.functions.View; -import java.util.function.Function; - /** * Prisms are {@link Iso Isos} that can fail in one direction. Example: *

@@ -63,7 +62,7 @@ public interface Prism extends
      *
      * @return a {@link Tuple2 tuple} of the two mappings encapsulated by this {@link Prism}
      */
-    default Tuple2, Function>> unPrism() {
+    default Tuple2, Fn1>> unPrism() {
         return Tuple2.fill(this., Identity, Identity, Identity,
                 Market>, Market>>apply(
                 new Market<>(Identity::new, Either::right)).fmap(Identity::runIdentity))
@@ -82,8 +81,8 @@ public interface Prism extends
      * @param  the input that guarantees its output
      * @return the {@link Prism}
      */
-    static  Prism prism(Function> sta,
-                                                Function bt) {
+    static  Prism prism(Fn1> sta,
+                                                Fn1 bt) {
         return new Prism() {
             @Override
             public > Optic, F, S, T, A, B> toOptic(
@@ -156,8 +155,8 @@ static  Prism prism(
      *                direction
      * @return the {@link Simple simple prism}
      */
-    static  Prism.Simple simplePrism(Function> sMaybeA,
-                                                 Function as) {
+    static  Prism.Simple simplePrism(Fn1> sMaybeA,
+                                                 Fn1 as) {
         return Prism.prism(s -> sMaybeA.apply(s).toEither(() -> s), as)::toOptic;
     }
 
diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java
index d15c8bfae..1e76ec4ce 100644
--- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java
+++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Over.java
@@ -6,8 +6,6 @@
 import com.jnape.palatable.lambda.functor.builtin.Identity;
 import com.jnape.palatable.lambda.optics.Optic;
 
-import java.util.function.Function;
-
 /**
  * Given an {@link Optic}, a function from A to B, and a "larger" value S,
  * produce a T by retrieving the A from the S, applying the function, and
@@ -24,7 +22,7 @@
  * @see View
  */
 public final class Over implements
-        Fn3, ? super Identity, S, T, A, B>, Function, S, T> {
+        Fn3, ? super Identity, S, T, A, B>, Fn1, S, T> {
 
     private static final Over INSTANCE = new Over<>();
 
@@ -33,7 +31,7 @@ private Over() {
 
     @Override
     public T checkedApply(Optic, ? super Identity, S, T, A, B> optic,
-                          Function fn,
+                          Fn1 fn,
                           S s) {
         return optic., Identity, Identity, Identity, Fn1>, Fn1>>apply(
                 a -> new Identity<>(fn.apply(a))).apply(s).runIdentity();
@@ -44,18 +42,18 @@ public static  Over over() {
         return (Over) INSTANCE;
     }
 
-    public static  Fn2, S, T> over(
+    public static  Fn2, S, T> over(
             Optic, ? super Identity, S, T, A, B> optic) {
         return Over.over().apply(optic);
     }
 
     public static  Fn1 over(Optic, ? super Identity, S, T, A, B> optic,
-                                              Function fn) {
+                                              Fn1 fn) {
         return over(optic).apply(fn);
     }
 
     public static  T over(Optic, ? super Identity, S, T, A, B> optic,
-                                      Function fn, S s) {
+                                      Fn1 fn, S s) {
         return over(optic, fn).apply(s);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java
index ce63ea01a..81b915867 100644
--- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java
+++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Under.java
@@ -8,8 +8,6 @@
 import com.jnape.palatable.lambda.optics.Iso;
 import com.jnape.palatable.lambda.optics.Optic;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
 
 /**
@@ -22,7 +20,9 @@
  * @param  the smaller type for focusing
  * @param  the smaller type for mirrored focusing
  */
-public final class Under implements Fn3, ? super Identity, S, T, A, B>, Function, B, A> {
+public final class Under implements
+        Fn3, ? super Identity, S, T, A, B>,
+                Fn1, B, A> {
 
     private static final Under INSTANCE = new Under<>();
 
@@ -31,7 +31,7 @@ private Under() {
 
     @Override
     public A checkedApply(Optic, ? super Identity, S, T, A, B> optic,
-                          Function fn,
+                          Fn1 fn,
                           B b) {
         Exchange> exchange = optic.apply(new Exchange<>(id(), Identity::new));
         return exchange.sa().apply(fn.apply(exchange.bt().apply(b).runIdentity()));
@@ -42,19 +42,19 @@ public static  Under under() {
         return (Under) INSTANCE;
     }
 
-    public static  Fn2, B, A> under(
+    public static  Fn2, B, A> under(
             Optic, ? super Identity, S, T, A, B> optic) {
         return Under.under().apply(optic);
     }
 
     public static  Fn1 under(
             Optic, ? super Identity, S, T, A, B> optic,
-            Function fn) {
+            Fn1 fn) {
         return under(optic).apply(fn);
     }
 
     public static  A under(Optic, ? super Identity, S, T, A, B> optic,
-                                       Function fn, B b) {
+                                       Fn1 fn, B b) {
         return under(optic, fn).apply(b);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java
index 9a8a8ee29..18ccd9faa 100644
--- a/src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java
+++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/CollectionLens.java
@@ -1,11 +1,11 @@
 package com.jnape.palatable.lambda.optics.lenses;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.optics.Lens;
 
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.function.Function;
 import java.util.stream.Stream;
 
 import static com.jnape.palatable.lambda.optics.Lens.simpleLens;
@@ -27,7 +27,7 @@ private CollectionLens() {
      * @param    the type of the collection
      * @return a lens that focuses on a copy of CX
      */
-    public static > Lens.Simple asCopy(Function copyFn) {
+    public static > Lens.Simple asCopy(Fn1 copyFn) {
         return simpleLens(copyFn, (__, copy) -> copy);
     }
 
@@ -40,8 +40,7 @@ public static > Lens.Simple asCopy(Function<
      * @param    the type of the collection
      * @return a lens that focuses on a Collection as a Set
      */
-    public static > Lens.Simple> asSet(
-            Function copyFn) {
+    public static > Lens.Simple> asSet(Fn1 copyFn) {
         return simpleLens(HashSet::new, (xsL, xsS) -> {
             Set missing = new HashSet<>(xsS);
             missing.removeAll(xsL);
@@ -65,7 +64,7 @@ public static > Lens.Simple> asSet(
      */
     @SuppressWarnings("RedundantTypeArguments")
     public static > Lens.Simple> asStream(
-            Function copyFn) {
+            Fn1 copyFn) {
         return simpleLens(Collection::stream, (xsL, xsS) -> {
             CX updated = copyFn.apply(xsL);
             updated.clear();
diff --git a/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java
index 3bab7f98c..b0bd8e810 100644
--- a/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java
+++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java
@@ -45,7 +45,7 @@ public static  Lens.Simple, Maybe> head() {
      * @return a lens focusing on the tail of an {@link Iterable}
      */
     public static  Lens.Simple, Iterable> tail() {
-        return simpleLens(Tail::tail, fn2(Head.head().andThen(o -> o.fmap(cons()).orElse(id()))).toBiFunction());
+        return simpleLens(Tail::tail, fn2(Head.head().fmap(o -> o.fmap(cons()).orElse(id()))));
     }
 
     /**
diff --git a/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java
index 63fb09016..7016716e7 100644
--- a/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java
+++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java
@@ -14,13 +14,15 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.adt.Maybe.maybe;
+import static com.jnape.palatable.lambda.functions.Effect.effect;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Alter.alter;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap;
+import static com.jnape.palatable.lambda.functions.specialized.SideEffect.sideEffect;
+import static com.jnape.palatable.lambda.io.IO.io;
 import static com.jnape.palatable.lambda.optics.Lens.Simple.adapt;
 import static com.jnape.palatable.lambda.optics.Lens.lens;
 import static com.jnape.palatable.lambda.optics.Lens.simpleLens;
@@ -47,7 +49,7 @@ private MapLens() {
      * @return a lens that focuses on copies of maps as a specific subtype
      */
     public static , K, V> Lens, M, M, M> asCopy(
-            Function, ? extends M> copyFn) {
+            Fn1, ? extends M> copyFn) {
         return lens(copyFn, (__, copy) -> copy);
     }
 
@@ -74,10 +76,10 @@ public static  Lens.Simple, Map> asCopy() {
      * @return a lens that focuses on the value at key, as a {@link Maybe}
      */
     public static , K, V> Lens, M, Maybe, Maybe> valueAt(
-            Function, ? extends M> copyFn, K k) {
+            Fn1, ? extends M> copyFn, K k) {
         return lens(m -> maybe(m.get(k)), (m, maybeV) -> maybeV
-                .>>fmap(v -> alter(updated -> updated.put(k, v)))
-                .orElse(alter(updated -> updated.remove(k)))
+                .>>fmap(v -> alter(effect(updated -> io(() -> updated.put(k, v)))))
+                .orElse(alter(updated -> io(sideEffect(() -> updated.remove(k)))))
                 .apply(copyFn.apply(m))
                 .unsafePerformIO());
     }
@@ -119,9 +121,9 @@ public static  Lens.Simple, V> valueAt(K k, V defaultValue) {
      */
     public static  Lens.Simple, Set> keys() {
         return simpleLens(m -> new HashSet<>(m.keySet()), (m, ks) -> {
-            HashSet ksCopy = new HashSet<>(ks);
-            Map updated = new HashMap<>(m);
-            Set keys = updated.keySet();
+            HashSet ksCopy  = new HashSet<>(ks);
+            Map  updated = new HashMap<>(m);
+            Set     keys    = updated.keySet();
             keys.retainAll(ksCopy);
             ksCopy.removeAll(keys);
             ksCopy.forEach(k -> updated.put(k, null));
@@ -142,11 +144,11 @@ public static  Lens.Simple, Set> keys() {
      */
     public static  Lens.Simple, Collection> values() {
         return simpleLens(m -> new ArrayList<>(m.values()), (m, vs) -> {
-            Map updated = new HashMap<>(m);
-            Set valueSet = new HashSet<>(vs);
+            Map updated  = new HashMap<>(m);
+            Set    valueSet = new HashSet<>(vs);
             Set matchingKeys = Filter.>filter(kv -> valueSet.contains(kv.getValue()))
-                    .andThen(map(Map.Entry::getKey))
-                    .andThen(toCollection(HashSet::new))
+                    .fmap(map(Map.Entry::getKey))
+                    .fmap(toCollection(HashSet::new))
                     .apply(updated.entrySet());
             updated.keySet().retainAll(matchingKeys);
             return updated;
diff --git a/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java
index a96e9eb46..3c2790d53 100644
--- a/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java
+++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java
@@ -1,12 +1,14 @@
 package com.jnape.palatable.lambda.optics.lenses;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.optics.Lens;
 
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.optics.Lens.simpleLens;
+import static java.util.Collections.singleton;
 
 /**
  * Lenses that operate on {@link Set}s.
@@ -16,6 +18,45 @@ public final class SetLens {
     private SetLens() {
     }
 
+    /**
+     * A lens that focuses on whether a {@link Set} contains all values in as. Note that
+     * copyFn is used to avoid mutating the {@link Set} in question.
+     *
+     * @param copyFn the copy function
+     * @param as     the values in question
+     * @param     the value type
+     * @param  the set to focus on
+     * @return a lens that focuses on the inclusion of a {@link Collection} of values in a given {@link Set}
+     */
+    public static > Lens.Simple intersection(
+            Fn1 copyFn,
+            Set as) {
+        return simpleLens(setA -> {
+                              SetA intersection = copyFn.apply(setA);
+                              intersection.retainAll(as);
+                              return intersection;
+                          },
+                          (setA, setB) -> {
+                              SetA copy = copyFn.apply(setA);
+                              copy.retainAll(setB);
+                              copy.retainAll(as);
+                              return copy;
+                          });
+    }
+
+    /**
+     * A lens that focuses on whether a {@link Set} contains some value a. Like
+     * {@link #intersection(Fn1, Set)} )} but with an implicit copy function that produces
+     * {@link HashSet}s.
+     *
+     * @param as  the values in question
+     * @param  the value type
+     * @return a lens that focuses on the inclusion of a {@link Collection} of values in a given {@link Set}
+     */
+    public static  Lens.Simple, Set> intersection(Set as) {
+        return intersection(HashSet::new, as);
+    }
+
     /**
      * A lens that focuses on whether a {@link Set} contains some value a. Note that copyFn is
      * used to avoid mutating the {@link Set} in question.
@@ -26,8 +67,8 @@ private SetLens() {
      * @param  the set to focus on
      * @return a lens that focuses on a value's inclusion in a given {@link Set}
      */
-    public static > Lens.Simple contains(
-            Function copyFn, A a) {
+    public static > Lens.Simple contains(Fn1 copyFn,
+                                                                               A a) {
         return simpleLens(setA -> setA.contains(a),
                           (setA, include) -> {
                               SetA copy = copyFn.apply(setA);
@@ -38,8 +79,8 @@ public static > Lens.Simple contains(
     }
 
     /**
-     * A lens that focuses on whether a {@link Set} contains some value a. Like {@link #contains(Function,
-     * Object)} but with an implicit copy function that produces {@link HashSet}s.
+     * A lens that focuses on whether a {@link Set} contains some value a. Like
+     * {@link #contains(Fn1, Object)} but with an implicit copy function that produces {@link HashSet}s.
      *
      * @param a   the value in question
      * @param  the value type
diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java b/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java
index 10d15de15..a061328ce 100644
--- a/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java
+++ b/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java
@@ -26,7 +26,7 @@ public interface Semigroup extends Fn2 {
      * @see FoldLeft
      */
     default A foldLeft(A a, Iterable as) {
-        return FoldLeft.foldLeft(toBiFunction(), a, as);
+        return FoldLeft.foldLeft(this, a, as);
     }
 
     /**
diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java
index 97ccfa54a..f39fd05cd 100644
--- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java
+++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java
@@ -32,7 +32,7 @@ private Absent() {
 
     @Override
     public Semigroup> checkedApply(Semigroup aSemigroup) {
-        return LiftA2., Maybe, Maybe, Maybe>liftA2(aSemigroup.toBiFunction())::apply;
+        return LiftA2., Maybe, Maybe, Maybe>liftA2(aSemigroup)::apply;
     }
 
     @SuppressWarnings("unchecked")
diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java
index bc97f7d9c..78d361ba8 100644
--- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java
+++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java
@@ -4,8 +4,6 @@
 import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory;
 import com.jnape.palatable.lambda.semigroup.Semigroup;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn3.LTBy.ltBy;
 
 /**
@@ -22,7 +20,7 @@
  * @see Max
  * @see MinBy
  */
-public final class MaxBy> implements SemigroupFactory, A> {
+public final class MaxBy> implements SemigroupFactory, A> {
 
     private static final MaxBy INSTANCE = new MaxBy<>();
 
@@ -30,7 +28,7 @@ private MaxBy() {
     }
 
     @Override
-    public Semigroup checkedApply(Function compareFn) {
+    public Semigroup checkedApply(Fn1 compareFn) {
         return (x, y) -> ltBy(compareFn, y, x) ? y : x;
     }
 
@@ -39,16 +37,15 @@ public static > MaxBy maxBy() {
         return (MaxBy) INSTANCE;
     }
 
-    public static > Semigroup maxBy(
-            Function compareFn) {
+    public static > Semigroup maxBy(Fn1 compareFn) {
         return MaxBy.maxBy().apply(compareFn);
     }
 
-    public static > Fn1 maxBy(Function compareFn, A x) {
+    public static > Fn1 maxBy(Fn1 compareFn, A x) {
         return MaxBy.maxBy(compareFn).apply(x);
     }
 
-    public static > A maxBy(Function compareFn, A x, A y) {
+    public static > A maxBy(Fn1 compareFn, A x, A y) {
         return maxBy(compareFn, x).apply(y);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java
index c425c5121..07ee12999 100644
--- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java
+++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinBy.java
@@ -4,8 +4,6 @@
 import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory;
 import com.jnape.palatable.lambda.semigroup.Semigroup;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn3.GTBy.gtBy;
 
 /**
@@ -22,7 +20,7 @@
  * @see Min
  * @see MaxBy
  */
-public final class MinBy> implements SemigroupFactory, A> {
+public final class MinBy> implements SemigroupFactory, A> {
 
     private static final MinBy INSTANCE = new MinBy<>();
 
@@ -30,7 +28,7 @@ private MinBy() {
     }
 
     @Override
-    public Semigroup checkedApply(Function compareFn) {
+    public Semigroup checkedApply(Fn1 compareFn) {
         return (x, y) -> gtBy(compareFn, y, x) ? y : x;
     }
 
@@ -39,16 +37,15 @@ public static > MinBy minBy() {
         return (MinBy) INSTANCE;
     }
 
-    public static > Semigroup minBy(
-            Function compareFn) {
+    public static > Semigroup minBy(Fn1 compareFn) {
         return MinBy.minBy().apply(compareFn);
     }
 
-    public static > Fn1 minBy(Function compareFn, A x) {
+    public static > Fn1 minBy(Fn1 compareFn, A x) {
         return MinBy.minBy(compareFn).apply(x);
     }
 
-    public static > A minBy(Function compareFn, A x, A y) {
+    public static > A minBy(Fn1 compareFn, A x, A y) {
         return minBy(compareFn, x).apply(y);
     }
 }
diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java
index 264fad155..8dcc439a3 100644
--- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java
+++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/RightAny.java
@@ -39,7 +39,7 @@ private RightAny() {
     public Semigroup> checkedApply(Semigroup rSemigroup) {
         return (x, y) -> x.match(constantly(y),
                                  xR -> y.match(constantly(right(xR)),
-                                               rSemigroup.apply(xR).andThen(Either::right)));
+                                               rSemigroup.apply(xR).fmap(Either::right)));
     }
 
     @SuppressWarnings("unchecked")
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 09222e719..b59ccfcc4 100644
--- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java
@@ -1,5 +1,6 @@
 package com.jnape.palatable.lambda.traversable;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.builtin.fn1.Empty;
 import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight;
 import com.jnape.palatable.lambda.functor.Applicative;
@@ -8,7 +9,6 @@
 
 import java.util.Iterator;
 import java.util.Objects;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons;
@@ -44,7 +44,7 @@ public Iterable unwrap() {
      * {@inheritDoc}
      */
     @Override
-    public  LambdaIterable fmap(Function fn) {
+    public  LambdaIterable fmap(Fn1 fn) {
         return wrap(map(fn, as));
     }
 
@@ -67,7 +67,7 @@ public  LambdaIterable pure(B b) {
      * @return the zipped LambdaIterable
      */
     @Override
-    public  LambdaIterable zip(Applicative, LambdaIterable> appFn) {
+    public  LambdaIterable zip(Applicative, LambdaIterable> appFn) {
         return Monad.super.zip(appFn).coerce();
     }
 
@@ -76,7 +76,7 @@ public  LambdaIterable zip(Applicative, L
      */
     @Override
     public  Lazy> lazyZip(
-            Lazy, LambdaIterable>> lazyAppFn) {
+            Lazy, LambdaIterable>> lazyAppFn) {
         return Empty.empty(as)
                ? lazy(LambdaIterable.empty())
                : Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce);
@@ -102,7 +102,7 @@ public  LambdaIterable discardR(Applicative> appB) {
      * {@inheritDoc}
      */
     @Override
-    public  LambdaIterable flatMap(Function>> f) {
+    public  LambdaIterable flatMap(Fn1>> f) {
         return wrap(flatten(map(a -> f.apply(a).>coerce().unwrap(), as)));
     }
 
@@ -113,11 +113,11 @@ public  LambdaIterable flatMap(Function, TravB extends Traversable>,
             AppB extends Applicative,
-            AppTrav extends Applicative> AppTrav traverse(Function fn,
-                                                                      Function pure) {
+            AppTrav extends Applicative> AppTrav traverse(Fn1 fn,
+                                                                      Fn1 pure) {
         return FoldRight.foldRight(
                 (a, lglb) -> fn.apply(a)
-                        .lazyZip(lglb., App>>fmap(appTrav -> appTrav
+                        .lazyZip(lglb., App>>fmap(appTrav -> appTrav
                                 .fmap(travB -> b -> (TravB) wrap(cons(b, ((LambdaIterable) travB).unwrap())))))
                         .fmap(appTrav -> (AppTrav) appTrav),
                 lazy(pure.apply((TravB) empty())),
diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java
index 9c9152f87..94a2e2e7c 100644
--- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java
+++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java
@@ -1,6 +1,6 @@
 package com.jnape.palatable.lambda.traversable;
 
-import com.jnape.palatable.lambda.functions.Fn2;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.functor.Functor;
 
@@ -8,9 +8,9 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
+import static com.jnape.palatable.lambda.functions.Fn2.fn2;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap;
@@ -40,7 +40,7 @@ public Map unwrap() {
     }
 
     @Override
-    public  LambdaMap fmap(Function fn) {
+    public  LambdaMap fmap(Fn1 fn) {
         return wrap(toMap(HashMap::new, map(entry -> tuple(entry.getKey(), fn.apply(entry.getValue())), map.entrySet())));
     }
 
@@ -48,13 +48,12 @@ public  LambdaMap fmap(Function fn) {
     @SuppressWarnings("unchecked")
     public , TravC extends Traversable>,
             AppC extends Applicative,
-            AppTrav extends Applicative> AppTrav traverse(Function fn,
-                                                                      Function pure) {
-        return foldLeft(Fn2., AppTrav>fn2(
-                appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> {
-                    ((LambdaMap) m).unwrap().put(k, v);
-                    return m;
-                })))).toBiFunction(),
+            AppTrav extends Applicative> AppTrav traverse(Fn1 fn,
+                                                                      Fn1 pure) {
+        return foldLeft(fn2(appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> {
+                            ((LambdaMap) m).unwrap().put(k, v);
+                            return m;
+                        })))),
                         pure.apply((TravC) LambdaMap.wrap(new HashMap<>())),
                         this.fmap(fn).unwrap().entrySet());
     }
diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java
index ec52e4e51..91d0a66c6 100644
--- a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java
+++ b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java
@@ -1,11 +1,10 @@
 package com.jnape.palatable.lambda.traversable;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.functor.Functor;
 import com.jnape.palatable.lambda.functor.builtin.Identity;
 
-import java.util.function.Function;
-
 /**
  * An interface for a class of data structures that can be "traversed from left to right" in a structure-preserving
  * way, successively applying some applicative computation to each element and collapsing the results into a single
@@ -36,21 +35,21 @@ public interface Traversable> extends Functorfn to each element of this traversable from left to right, and collapse the results into
      * a single resulting applicative, potentially with the assistance of the applicative's pure function.
      *
-     * @param fn        the function to apply
-     * @param pure      the applicative pure function
      * @param        the resulting element type
      * @param      the result applicative type
      * @param    this Traversable instance over B
      * @param     the result applicative instance over B
      * @param  the full inferred resulting type from the traversal
+     * @param fn        the function to apply
+     * @param pure      the applicative pure function
      * @return the traversed Traversable, wrapped inside an applicative
      */
     , TravB extends Traversable, AppB extends Applicative,
             AppTrav extends Applicative> AppTrav traverse(
-            Function fn, Function pure);
+            Fn1 fn, Fn1 pure);
 
     @Override
-    default  Traversable fmap(Function fn) {
+    default  Traversable fmap(Fn1 fn) {
         return traverse(a -> new Identity(fn.apply(a)), Identity::new).runIdentity();
     }
 }
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java
index 833447905..37371ead6 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java
@@ -1,5 +1,6 @@
 package com.jnape.palatable.lambda.adt;
 
+import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.framework.Subjects;
 import com.jnape.palatable.traitor.runners.Traits;
@@ -15,7 +16,6 @@
 
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.BiFunction;
 
 import static com.jnape.palatable.lambda.adt.Either.fromMaybe;
 import static com.jnape.palatable.lambda.adt.Either.left;
@@ -23,6 +23,7 @@
 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.Unit.UNIT;
+import static com.jnape.palatable.lambda.functions.Effect.fromConsumer;
 import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy;
 import static com.jnape.palatable.traitor.framework.Subjects.subjects;
 import static org.hamcrest.core.Is.is;
@@ -42,7 +43,7 @@ public Subjects> testSubjects() {
 
     @Test
     public void recoverLiftsLeftAndFlattensRight() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         assertThat(left.recover(l -> -1), is(-1));
@@ -51,7 +52,7 @@ public void recoverLiftsLeftAndFlattensRight() {
 
     @Test
     public void forfeitLiftsRightAndFlattensLeft() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         assertThat(left.forfeit(r -> "bar"), is("foo"));
@@ -60,7 +61,7 @@ public void forfeitLiftsRightAndFlattensLeft() {
 
     @Test
     public void orReplacesLeftAndFlattensRight() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         assertThat(left.or(-1), is(-1));
@@ -69,7 +70,7 @@ public void orReplacesLeftAndFlattensRight() {
 
     @Test
     public void orThrowFlattensRightOrThrowsException() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         assertThat(right.orThrow(IllegalStateException::new), is(1));
@@ -82,7 +83,7 @@ public void orThrowFlattensRightOrThrowsException() {
 
     @Test
     public void filterLiftsRight() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         assertThat(left.filter(x -> true, () -> "bar"), is(left));
@@ -93,7 +94,7 @@ public void filterLiftsRight() {
 
     @Test
     public void filterSupportsFunctionFromRToL() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         assertThat(left.filter(x -> true, Object::toString), is(left));
@@ -104,7 +105,7 @@ public void filterSupportsFunctionFromRToL() {
 
     @Test
     public void monadicFlatMapLiftsRightAndFlattensBackToEither() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         assertThat(left.flatMap(r -> right(r + 1)), is(left("foo")));
@@ -113,14 +114,14 @@ public void monadicFlatMapLiftsRightAndFlattensBackToEither() {
 
     @Test
     public void mergeDuallyLiftsAndCombinesBiasingLeft() {
-        Either left1 = left("foo");
+        Either left1  = left("foo");
         Either right1 = right(1);
 
-        Either left2 = left("bar");
+        Either left2  = left("bar");
         Either right2 = right(2);
 
-        BiFunction concat = String::concat;
-        BiFunction add = (r1, r2) -> r1 + r2;
+        Fn2    concat = String::concat;
+        Fn2 add    = Integer::sum;
 
         assertThat(left1.merge(concat, add, left2), is(left("foobar")));
         assertThat(left1.merge(concat, add, right2), is(left1));
@@ -130,7 +131,7 @@ public void mergeDuallyLiftsAndCombinesBiasingLeft() {
 
     @Test
     public void matchDuallyLiftsAndFlattens() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         assertThat(left.match(l -> l + "bar", r -> r + 1), is("foobar"));
@@ -145,7 +146,7 @@ public void toMaybeMapsEitherToOptional() {
 
     @Test
     public void fromMaybeMapsMaybeToEither() {
-        Maybe just = just(1);
+        Maybe just    = just(1);
         Maybe nothing = nothing();
 
         assertThat(fromMaybe(just, () -> "fail"), is(right(1)));
@@ -154,8 +155,8 @@ public void fromMaybeMapsMaybeToEither() {
 
     @Test
     public void fromMaybeDoesNotEvaluateLeftFnForRight() {
-        Maybe just = just(1);
-        AtomicInteger atomicInteger = new AtomicInteger(0);
+        Maybe just          = just(1);
+        AtomicInteger  atomicInteger = new AtomicInteger(0);
         fromMaybe(just, atomicInteger::incrementAndGet);
 
         assertThat(atomicInteger.get(), is(0));
@@ -196,31 +197,31 @@ public void monadTryingWithRunnable() {
 
     @Test
     public void monadicPeekLiftsIOToTheRight() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         AtomicInteger intRef = new AtomicInteger();
 
-        left.peek(intRef::set);
+        left.peek(fromConsumer(intRef::set));
         assertEquals(0, intRef.get());
 
-        right.peek(intRef::set);
+        right.peek(fromConsumer(intRef::set));
         assertEquals(1, intRef.get());
     }
 
     @Test
     public void dyadicPeekDuallyLiftsIO() {
-        Either left = left("foo");
+        Either left  = left("foo");
         Either right = right(1);
 
         AtomicReference stringRef = new AtomicReference<>();
-        AtomicInteger intRef = new AtomicInteger();
+        AtomicInteger           intRef    = new AtomicInteger();
 
-        left.peek(stringRef::set, intRef::set);
+        left.peek(fromConsumer(stringRef::set), fromConsumer(intRef::set));
         assertEquals("foo", stringRef.get());
         assertEquals(0, intRef.get());
 
-        right.peek(stringRef::set, intRef::set);
+        right.peek(fromConsumer(stringRef::set), fromConsumer(intRef::set));
         assertEquals("foo", stringRef.get());
         assertEquals(1, intRef.get());
     }
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java
index fc21833dc..281f00cf8 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java
@@ -21,6 +21,7 @@
 import static com.jnape.palatable.lambda.adt.Maybe.nothing;
 import static com.jnape.palatable.lambda.adt.Unit.UNIT;
 import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
+import static com.jnape.palatable.lambda.functions.Effect.fromConsumer;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq;
 import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy;
 import static com.jnape.palatable.traitor.framework.Subjects.subjects;
@@ -97,10 +98,10 @@ public void fromEither() {
     @Test
     public void peek() {
         AtomicInteger ref = new AtomicInteger(0);
-        assertEquals(just(1), just(1).peek(__ -> ref.incrementAndGet()));
+        assertEquals(just(1), just(1).peek(fromConsumer(__ -> ref.incrementAndGet())));
         assertEquals(1, ref.get());
 
-        assertEquals(nothing(), nothing().peek(__ -> ref.incrementAndGet()));
+        assertEquals(nothing(), nothing().peek(fromConsumer(__ -> ref.incrementAndGet())));
         assertEquals(1, ref.get());
     }
 
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java
index 0606c892d..f818d4fd7 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java
@@ -1,6 +1,7 @@
 package com.jnape.palatable.lambda.adt.choice;
 
 import com.jnape.palatable.lambda.adt.coproduct.CoProduct5;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.framework.Subjects;
 import com.jnape.palatable.traitor.runners.Traits;
@@ -13,8 +14,6 @@
 import testsupport.traits.MonadLaws;
 import testsupport.traits.TraversableLaws;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.adt.choice.Choice6.a;
 import static com.jnape.palatable.lambda.adt.choice.Choice6.b;
 import static com.jnape.palatable.lambda.adt.choice.Choice6.c;
@@ -52,7 +51,7 @@ public Subjects> test
 
     @Test
     public void convergeStaysInChoice() {
-        Function> convergenceFn = f -> Choice5.b(f.toString());
+        Fn1> convergenceFn = f -> Choice5.b(f.toString());
 
         assertEquals(Choice5.a(1), a.converge(convergenceFn));
         assertEquals(Choice5.b("two"), b.converge(convergenceFn));
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java
index 5bec8a5b4..62f2e52d0 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java
@@ -1,6 +1,7 @@
 package com.jnape.palatable.lambda.adt.choice;
 
 import com.jnape.palatable.lambda.adt.coproduct.CoProduct6;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.framework.Subjects;
 import com.jnape.palatable.traitor.runners.Traits;
@@ -13,8 +14,6 @@
 import testsupport.traits.MonadLaws;
 import testsupport.traits.TraversableLaws;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.adt.choice.Choice7.a;
 import static com.jnape.palatable.lambda.adt.choice.Choice7.b;
 import static com.jnape.palatable.lambda.adt.choice.Choice7.c;
@@ -55,7 +54,7 @@ public Subjects> convergenceFn = g -> Choice6.b(g.toString());
+        Fn1> convergenceFn = g -> Choice6.b(g.toString());
 
         assertEquals(Choice6.a(1), a.converge(convergenceFn));
         assertEquals(Choice6.b("two"), b.converge(convergenceFn));
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java
index d71e3228d..2b3d4dbe7 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java
@@ -1,6 +1,7 @@
 package com.jnape.palatable.lambda.adt.choice;
 
 import com.jnape.palatable.lambda.adt.coproduct.CoProduct7;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.framework.Subjects;
 import com.jnape.palatable.traitor.runners.Traits;
@@ -13,8 +14,6 @@
 import testsupport.traits.MonadLaws;
 import testsupport.traits.TraversableLaws;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.adt.choice.Choice8.a;
 import static com.jnape.palatable.lambda.adt.choice.Choice8.b;
 import static com.jnape.palatable.lambda.adt.choice.Choice8.c;
@@ -58,7 +57,8 @@ public Subjects> convergenceFn = h -> Choice7.b(h.toString());
+        Fn1> convergenceFn =
+                h -> Choice7.b(h.toString());
 
         assertEquals(Choice7.a(1), a.converge(convergenceFn));
         assertEquals(Choice7.b("two"), b.converge(convergenceFn));
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2Test.java
index 8b3d8f978..d5a07cca6 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct2Test.java
@@ -1,11 +1,10 @@
 package com.jnape.palatable.lambda.adt.coproduct;
 
 import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.function.Function;
-
 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;
@@ -21,13 +20,13 @@ public class CoProduct2Test {
     public void setUp() {
         a = new CoProduct2>() {
             @Override
-            public  R match(Function aFn, Function bFn) {
+            public  R match(Fn1 aFn, Fn1 bFn) {
                 return aFn.apply(1);
             }
         };
         b = new CoProduct2>() {
             @Override
-            public  R match(Function aFn, Function bFn) {
+            public  R match(Fn1 aFn, Fn1 bFn) {
                 return bFn.apply(true);
             }
         };
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3Test.java
index 49af8665c..c80a50be2 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct3Test.java
@@ -3,11 +3,10 @@
 import com.jnape.palatable.lambda.adt.Maybe;
 import com.jnape.palatable.lambda.adt.choice.Choice2;
 import com.jnape.palatable.lambda.adt.choice.Choice3;
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.function.Function;
-
 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;
@@ -24,22 +23,22 @@ public class CoProduct3Test {
     public void setUp() {
         a = new CoProduct3>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn) {
                 return aFn.apply(1);
             }
         };
         b = new CoProduct3>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn) {
                 return bFn.apply("two");
             }
         };
         c = new CoProduct3>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn) {
                 return cFn.apply(true);
             }
         };
@@ -61,7 +60,7 @@ public void diverge() {
 
     @Test
     public void converge() {
-        Function> convergenceFn = x -> x ? Choice2.a(-1) : Choice2.b("false");
+        Fn1> convergenceFn = x -> x ? Choice2.a(-1) : Choice2.b("false");
         assertEquals(1, a.converge(convergenceFn).match(id(), id()));
         assertEquals("two", b.converge(convergenceFn).match(id(), id()));
         assertEquals(-1, c.converge(convergenceFn).match(id(), id()));
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java
index 840416088..810a1781c 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4Test.java
@@ -3,11 +3,10 @@
 import com.jnape.palatable.lambda.adt.Maybe;
 import com.jnape.palatable.lambda.adt.choice.Choice3;
 import com.jnape.palatable.lambda.adt.choice.Choice4;
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.function.Function;
-
 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;
@@ -25,29 +24,29 @@ public class CoProduct4Test {
     public void setUp() {
         a = new CoProduct4>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn) {
                 return aFn.apply(1);
             }
         };
         b = new CoProduct4>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn) {
                 return bFn.apply("two");
             }
         };
         c = new CoProduct4>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn) {
                 return cFn.apply(true);
             }
         };
         d = new CoProduct4>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn) {
                 return dFn.apply(4D);
             }
         };
@@ -71,11 +70,12 @@ public void diverge() {
 
     @Test
     public void converge() {
-        Function> convergenceFn = x -> x.equals(1d)
-                                                                                       ? Choice3.a(1)
-                                                                                       : x.equals(2d)
-                                                                                         ? Choice3.b("b")
-                                                                                         : Choice3.c(false);
+        Fn1> convergenceFn = x ->
+                x.equals(1d)
+                ? Choice3.a(1)
+                : x.equals(2d)
+                  ? Choice3.b("b")
+                  : Choice3.c(false);
         assertEquals(1, a.converge(convergenceFn).match(id(), id(), id()));
         assertEquals("two", b.converge(convergenceFn).match(id(), id(), id()));
         assertEquals(true, c.converge(convergenceFn).match(id(), id(), id()));
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5Test.java
index 14cccc369..bd986dea1 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct5Test.java
@@ -3,11 +3,10 @@
 import com.jnape.palatable.lambda.adt.Maybe;
 import com.jnape.palatable.lambda.adt.choice.Choice4;
 import com.jnape.palatable.lambda.adt.choice.Choice5;
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.function.Function;
-
 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;
@@ -26,41 +25,41 @@ public class CoProduct5Test {
     public void setUp() {
         a = new CoProduct5>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn) {
                 return aFn.apply(1);
             }
         };
         b = new CoProduct5>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn) {
                 return bFn.apply("two");
             }
         };
         c = new CoProduct5>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn) {
                 return cFn.apply(true);
             }
         };
         d = new CoProduct5>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn) {
                 return dFn.apply(4d);
             }
         };
         e = new CoProduct5>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn) {
                 return eFn.apply('z');
             }
         };
@@ -86,13 +85,13 @@ public void diverge() {
 
     @Test
     public void converge() {
-        Function> convergenceFn = x -> x.equals('a')
-                                                                                                  ? Choice4.a(1)
-                                                                                                  : x.equals('b')
-                                                                                                    ? Choice4.b("b")
-                                                                                                    : x.equals('c')
-                                                                                                      ? Choice4.c(false)
-                                                                                                      : Choice4.d(1D);
+        Fn1> convergenceFn = x -> x.equals('a')
+                                                                                             ? Choice4.a(1)
+                                                                                             : x.equals('b')
+                                                                                               ? Choice4.b("b")
+                                                                                               : x.equals('c')
+                                                                                                 ? Choice4.c(false)
+                                                                                                 : Choice4.d(1D);
         assertEquals(1, a.converge(convergenceFn).match(id(), id(), id(), id()));
         assertEquals("two", b.converge(convergenceFn).match(id(), id(), id(), id()));
         assertEquals(true, c.converge(convergenceFn).match(id(), id(), id(), id()));
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6Test.java
index 8c38290e7..924e0507f 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6Test.java
@@ -3,11 +3,10 @@
 import com.jnape.palatable.lambda.adt.Maybe;
 import com.jnape.palatable.lambda.adt.choice.Choice5;
 import com.jnape.palatable.lambda.adt.choice.Choice6;
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.function.Function;
-
 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;
@@ -27,49 +26,49 @@ public class CoProduct6Test {
     public void setUp() {
         a = new CoProduct6>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn) {
                 return aFn.apply(1);
             }
         };
         b = new CoProduct6>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn) {
                 return bFn.apply("two");
             }
         };
         c = new CoProduct6>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn) {
                 return cFn.apply(true);
             }
         };
         d = new CoProduct6>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn) {
                 return dFn.apply(4D);
             }
         };
         e = new CoProduct6>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn) {
                 return eFn.apply('z');
             }
         };
         f = new CoProduct6>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn) {
                 return fFn.apply(5L);
             }
         };
@@ -97,7 +96,7 @@ public void diverge() {
 
     @Test
     public void converge() {
-        Function> convergenceFn = x ->
+        Fn1> convergenceFn = x ->
                 x.equals(1L)
                 ? Choice5.a(1)
                 : x.equals(2L)
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7Test.java
index 1ae73c596..84999f677 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct7Test.java
@@ -3,11 +3,10 @@
 import com.jnape.palatable.lambda.adt.Maybe;
 import com.jnape.palatable.lambda.adt.choice.Choice6;
 import com.jnape.palatable.lambda.adt.choice.Choice7;
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.function.Function;
-
 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;
@@ -28,64 +27,64 @@ public class CoProduct7Test {
     public void setUp() {
         a = new CoProduct7>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn) {
                 return aFn.apply(1);
             }
         };
         b = new CoProduct7>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn) {
                 return bFn.apply("two");
             }
         };
         c = new CoProduct7>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn) {
                 return cFn.apply(true);
             }
         };
         d = new CoProduct7>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn) {
                 return dFn.apply(4D);
             }
         };
         e = new CoProduct7>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn) {
                 return eFn.apply('z');
             }
         };
         f = new CoProduct7>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn) {
                 return fFn.apply(5L);
             }
         };
         g = new CoProduct7>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn) {
                 return gFn.apply(6f);
             }
         };
@@ -115,7 +114,7 @@ public void diverge() {
 
     @Test
     public void converge() {
-        Function> convergenceFn = x ->
+        Fn1> convergenceFn = x ->
                 x.equals(1f)
                 ? Choice6.a(1)
                 : x.equals(2f)
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8Test.java
index e85f3152a..e5620b3c0 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct8Test.java
@@ -3,11 +3,10 @@
 import com.jnape.palatable.lambda.adt.Maybe;
 import com.jnape.palatable.lambda.adt.choice.Choice7;
 import com.jnape.palatable.lambda.adt.choice.Choice8;
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.function.Function;
-
 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;
@@ -29,73 +28,73 @@ public class CoProduct8Test {
     public void setUp() {
         a = new CoProduct8>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn, Function hFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn, Fn1 hFn) {
                 return aFn.apply(1);
             }
         };
         b = new CoProduct8>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn, Function hFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn, Fn1 hFn) {
                 return bFn.apply("two");
             }
         };
         c = new CoProduct8>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn, Function hFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn, Fn1 hFn) {
                 return cFn.apply(true);
             }
         };
         d = new CoProduct8>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn, Function hFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn, Fn1 hFn) {
                 return dFn.apply(4D);
             }
         };
         e = new CoProduct8>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn, Function hFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn, Fn1 hFn) {
                 return eFn.apply('z');
             }
         };
         f = new CoProduct8>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn, Function hFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn, Fn1 hFn) {
                 return fFn.apply(5L);
             }
         };
         g = new CoProduct8>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn, Function hFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn, Fn1 hFn) {
                 return gFn.apply(6f);
             }
         };
         h = new CoProduct8>() {
             @Override
-            public  R match(Function aFn, Function bFn,
-                               Function cFn, Function dFn,
-                               Function eFn, Function fFn,
-                               Function gFn, Function hFn) {
+            public  R match(Fn1 aFn, Fn1 bFn,
+                               Fn1 cFn, Fn1 dFn,
+                               Fn1 eFn, Fn1 fFn,
+                               Fn1 gFn, Fn1 hFn) {
                 return hFn.apply((short) 7);
             }
         };
@@ -115,7 +114,7 @@ public void match() {
 
     @Test
     public void converge() {
-        Function> convergenceFn = x ->
+        Fn1> convergenceFn = x ->
                 x.equals((short) 1)
                 ? Choice7.a(1)
                 : x.equals((short) 2)
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java
index a72f4843a..e4a4ee0bb 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java
@@ -1,5 +1,6 @@
 package com.jnape.palatable.lambda.adt.hlist;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.runners.Traits;
 import org.junit.Before;
@@ -62,7 +63,7 @@ public void accessors() {
     @Test
     public void randomAccess() {
         SingletonHList spiedTail = spy(singletonHList("second"));
-        Tuple2 tuple2 = new Tuple2<>("first", spiedTail);
+        Tuple2 tuple2    = new Tuple2<>("first", spiedTail);
 
         verify(spiedTail, only()).head();
         tuple2._1();
@@ -104,15 +105,15 @@ public void staticFactoryMethodFromMapEntry() {
 
     @Test
     public void zipPrecedence() {
-        Tuple2 a = tuple("foo", 1);
-        Tuple2> b = tuple("bar", x -> x + 1);
+        Tuple2                                 a = tuple("foo", 1);
+        Tuple2> b = tuple("bar", x -> x + 1);
         assertEquals(tuple("bar", 2), a.zip(b));
     }
 
     @Test
     public void flatMapPrecedence() {
-        Tuple2 a = tuple("foo", 1);
-        Function> b = x -> tuple("bar", x + 1);
+        Tuple2               a = tuple("foo", 1);
+        Fn1> b = x -> tuple("bar", x + 1);
         assertEquals(tuple("foo", 2), a.flatMap(b));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java
index 8ca30d9af..4a086c5f4 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java
@@ -1,5 +1,6 @@
 package com.jnape.palatable.lambda.adt.hlist;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.runners.Traits;
 import org.junit.Before;
@@ -83,15 +84,15 @@ public void fill() {
 
     @Test
     public void zipPrecedence() {
-        Tuple3 a = tuple("foo", 1, 2);
-        Tuple3> b = tuple("bar", 2, x -> x + 1);
+        Tuple3                                 a = tuple("foo", 1, 2);
+        Tuple3> b = tuple("bar", 2, x -> x + 1);
         assertEquals(tuple("foo", 1, 3), a.zip(b));
     }
 
     @Test
     public void flatMapPrecedence() {
-        Tuple3 a = tuple("foo", 1, 2);
-        Function> b = x -> tuple("bar", 2, x + 1);
+        Tuple3               a = tuple("foo", 1, 2);
+        Fn1> b = x -> tuple("bar", 2, x + 1);
         assertEquals(tuple("foo", 1, 3), a.flatMap(b));
     }
 }
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java
index 7eff60484..59280ec53 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java
@@ -1,5 +1,6 @@
 package com.jnape.palatable.lambda.adt.hlist;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.runners.Traits;
 import org.junit.Before;
@@ -60,8 +61,8 @@ public void accessors() {
 
     @Test
     public void randomAccess() {
-        Tuple3 spiedTail = spy(tuple("second", "third", "fourth"));
-        Tuple4 tuple4 = new Tuple4<>("first", spiedTail);
+        Tuple3         spiedTail = spy(tuple("second", "third", "fourth"));
+        Tuple4 tuple4    = new Tuple4<>("first", spiedTail);
 
         verify(spiedTail, times(1))._1();
         verify(spiedTail, times(1))._2();
@@ -86,15 +87,15 @@ public void fill() {
 
     @Test
     public void zipPrecedence() {
-        Tuple4 a = tuple("foo", 1, 2, 3);
-        Tuple4> b = tuple("foo", 1, 2, x -> x + 1);
+        Tuple4                                 a = tuple("foo", 1, 2, 3);
+        Tuple4> b = tuple("foo", 1, 2, x -> x + 1);
         assertEquals(tuple("foo", 1, 2, 4), a.zip(b));
     }
 
     @Test
     public void flatMapPrecedence() {
-        Tuple4 a = tuple("foo", 1, 2, 3);
-        Function> b = x -> tuple("bar", 2, 3, x + 1);
+        Tuple4               a = tuple("foo", 1, 2, 3);
+        Fn1> b = x -> tuple("bar", 2, 3, x + 1);
         assertEquals(tuple("foo", 1, 2, 4), a.flatMap(b));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java
index 22d30223d..970ee1c62 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java
@@ -1,6 +1,7 @@
 package com.jnape.palatable.lambda.adt.hlist;
 
 import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.runners.Traits;
 import org.junit.Before;
@@ -62,8 +63,8 @@ public void accessors() {
 
     @Test
     public void randomAccess() {
-        Tuple4 spiedTail = spy(tuple("second", "third", "fourth", "fifth"));
-        Tuple5 tuple5 = new Tuple5<>("first", spiedTail);
+        Tuple4         spiedTail = spy(tuple("second", "third", "fourth", "fifth"));
+        Tuple5 tuple5    = new Tuple5<>("first", spiedTail);
 
         verify(spiedTail, times(1))._1();
         verify(spiedTail, times(1))._2();
@@ -90,15 +91,17 @@ public void fill() {
 
     @Test
     public void zipPrecedence() {
-        Tuple5 a = tuple("foo", 1, 2, 3, 4);
-        Tuple5> b = tuple("bar", 2, 3, 4, x -> x + 1);
+        Tuple5 a =
+                tuple("foo", 1, 2, 3, 4);
+        Tuple5> b =
+                tuple("bar", 2, 3, 4, x -> x + 1);
         assertEquals(tuple("bar", 2, 3, 4, 5), a.zip(b));
     }
 
     @Test
     public void flatMapPrecedence() {
-        Tuple5 a = tuple("foo", 1, 2, 3, 4);
-        Function> b = x -> tuple("bar", 2, 3, 4, x + 1);
+        Tuple5               a = tuple("foo", 1, 2, 3, 4);
+        Fn1> b = x -> tuple("bar", 2, 3, 4, x + 1);
         assertEquals(tuple("foo", 1, 2, 3, 5), a.flatMap(b));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java
index af12149e6..796ed4752 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java
@@ -1,6 +1,7 @@
 package com.jnape.palatable.lambda.adt.hlist;
 
 import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.runners.Traits;
 import org.junit.Before;
@@ -64,8 +65,8 @@ public void accessors() {
 
     @Test
     public void randomAccess() {
-        Tuple5 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth"));
-        Tuple6 tuple6 = new Tuple6<>("first", spiedTail);
+        Tuple5         spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth"));
+        Tuple6 tuple6    = new Tuple6<>("first", spiedTail);
 
         verify(spiedTail, times(1))._1();
         verify(spiedTail, times(1))._2();
@@ -94,15 +95,17 @@ public void fill() {
 
     @Test
     public void zipPrecedence() {
-        Tuple6 a = tuple("foo", 1, 2, 3, 4, 5);
-        Tuple6> b = tuple("bar", 2, 3, 4, 5, x -> x + 1);
+        Tuple6 a =
+                tuple("foo", 1, 2, 3, 4, 5);
+        Tuple6> b =
+                tuple("bar", 2, 3, 4, 5, x -> x + 1);
         assertEquals(tuple("bar", 2, 3, 4, 5, 6), a.zip(b));
     }
 
     @Test
     public void flatMapPrecedence() {
-        Tuple6 a = tuple("foo", 1, 2, 3, 4, 5);
-        Function> b = x -> tuple("bar", 2, 3, 4, 5, x + 1);
+        Tuple6               a = tuple("foo", 1, 2, 3, 4, 5);
+        Fn1> b = x -> tuple("bar", 2, 3, 4, 5, x + 1);
         assertEquals(tuple("foo", 1, 2, 3, 4, 6), a.flatMap(b));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java
index f4fd5442e..b8c07e3db 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java
@@ -1,6 +1,7 @@
 package com.jnape.palatable.lambda.adt.hlist;
 
 import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.runners.Traits;
 import org.junit.Before;
@@ -65,8 +66,8 @@ public void accessors() {
 
     @Test
     public void randomAccess() {
-        Tuple6 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh"));
-        Tuple7 tuple7 = new Tuple7<>("first", spiedTail);
+        Tuple6         spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh"));
+        Tuple7 tuple7    = new Tuple7<>("first", spiedTail);
 
         verify(spiedTail, times(1))._1();
         verify(spiedTail, times(1))._2();
@@ -97,15 +98,17 @@ public void into() {
 
     @Test
     public void zipPrecedence() {
-        Tuple7 a = tuple("foo", 1, 2, 3, 4, 5, 6);
-        Tuple7> b = tuple("bar", 2, 3, 4, 5, 6, x -> x + 1);
+        Tuple7 a =
+                tuple("foo", 1, 2, 3, 4, 5, 6);
+        Tuple7> b =
+                tuple("bar", 2, 3, 4, 5, 6, x -> x + 1);
         assertEquals(tuple("bar", 2, 3, 4, 5, 6, 7), a.zip(b));
     }
 
     @Test
     public void flatMapPrecedence() {
-        Tuple7 a = tuple("foo", 1, 2, 3, 4, 5, 6);
-        Function> b = x -> tuple("bar", 2, 3, 4, 5, 6, x + 1);
+        Tuple7               a = tuple("foo", 1, 2, 3, 4, 5, 6);
+        Fn1> b = x -> tuple("bar", 2, 3, 4, 5, 6, x + 1);
         assertEquals(tuple("foo", 1, 2, 3, 4, 5, 7), a.flatMap(b));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java
index 327fb8fe3..6c788a83d 100644
--- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java
@@ -1,6 +1,7 @@
 package com.jnape.palatable.lambda.adt.hlist;
 
 import com.jnape.palatable.lambda.adt.hlist.HList.HCons;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.runners.Traits;
 import org.junit.Before;
@@ -12,8 +13,6 @@
 import testsupport.traits.MonadLaws;
 import testsupport.traits.TraversableLaws;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.spy;
@@ -66,8 +65,8 @@ public void accessors() {
 
     @Test
     public void randomAccess() {
-        Tuple7 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh", "eighth"));
-        Tuple8 tuple8 = new Tuple8<>("first", spiedTail);
+        Tuple7         spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh", "eighth"));
+        Tuple8 tuple8    = new Tuple8<>("first", spiedTail);
 
         verify(spiedTail, times(1))._1();
         verify(spiedTail, times(1))._2();
@@ -100,15 +99,19 @@ public void into() {
 
     @Test
     public void zipPrecedence() {
-        Tuple8 a = tuple("foo", 1, 2, 3, 4, 5, 6, 7);
-        Tuple8> b = tuple("bar", 2, 3, 4, 5, 6, 7, x -> x + 1);
+        Tuple8 a
+                = tuple("foo", 1, 2, 3, 4, 5, 6, 7);
+        Tuple8> b
+                = tuple("bar", 2, 3, 4, 5, 6, 7, x -> x + 1);
         assertEquals(tuple("bar", 2, 3, 4, 5, 6, 7, 8), a.zip(b));
     }
 
     @Test
     public void flatMapPrecedence() {
-        Tuple8 a = tuple("foo", 1, 2, 3, 4, 5, 6, 7);
-        Function> b = x -> tuple("bar", 2, 3, 4, 5, 6, 7, x + 1);
+        Tuple8 a =
+                tuple("foo", 1, 2, 3, 4, 5, 6, 7);
+        Fn1> b =
+                x -> tuple("bar", 2, 3, 4, 5, 6, 7, x + 1);
         assertEquals(tuple("foo", 1, 2, 3, 4, 5, 6, 8), a.flatMap(b));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java
index ca3505a0e..c0a442762 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java
@@ -1,16 +1,20 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.Unit;
+import com.jnape.palatable.lambda.io.IO;
 import org.junit.Test;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 
 import static com.jnape.palatable.lambda.adt.Unit.UNIT;
 import static com.jnape.palatable.lambda.functions.Effect.effect;
+import static com.jnape.palatable.lambda.functions.Effect.fromConsumer;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
 import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
 import static org.junit.Assert.assertEquals;
 
 public class EffectTest {
@@ -19,21 +23,17 @@ public class EffectTest {
     public void covariantReturns() {
         List results = new ArrayList<>();
 
-        Effect effect       = results::add;
+        Effect effect       = fromConsumer(results::add);
         Effect diMapL       = effect.diMapL(Object::toString);
         Effect contraMap    = effect.contraMap(Object::toString);
-        Effect compose      = effect.compose(Object::toString);
         Effect stringEffect = effect.discardR(constantly("1"));
-        Effect andThen      = effect.andThen(effect);
 
-        effect.accept("1");
-        diMapL.accept("2");
-        contraMap.accept("3");
-        compose.accept("4");
-        stringEffect.accept("5");
-        andThen.accept("6");
+        effect.apply("1").unsafePerformIO();
+        diMapL.apply("2").unsafePerformIO();
+        contraMap.apply("3").unsafePerformIO();
+        stringEffect.apply("4").unsafePerformIO();
 
-        assertEquals(asList("1", "2", "3", "4", "5", "6", "6"), results);
+        assertEquals(asList("1", "2", "3", "4"), results);
     }
 
     @Test
@@ -44,8 +44,17 @@ public void staticFactoryMethods() {
         runnableEffect.apply(UNIT).unsafePerformIO();
         assertEquals(1, counter.get());
 
-        Effect fnEffect = effect(AtomicInteger::incrementAndGet);
+        Effect fnEffect = Effect.fromConsumer(AtomicInteger::incrementAndGet);
         fnEffect.apply(counter).unsafePerformIO();
         assertEquals(2, counter.get());
     }
+
+    @Test
+    public void toConsumer() {
+        @SuppressWarnings("RedundantTypeArguments") Effect> addFoo   = l -> IO.io(() -> l.add("foo"));
+        Consumer>                                           consumer = addFoo.toConsumer();
+        ArrayList                                                list     = new ArrayList<>();
+        consumer.accept(list);
+        assertEquals(singletonList("foo"), list);
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java
new file mode 100644
index 000000000..87af14209
--- /dev/null
+++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn0Test.java
@@ -0,0 +1,39 @@
+package com.jnape.palatable.lambda.functions;
+
+import org.junit.Test;
+
+import java.util.concurrent.Callable;
+import java.util.function.Supplier;
+
+import static org.junit.Assert.assertEquals;
+
+public class Fn0Test {
+
+    @Test
+    public void fromSupplier() {
+        Supplier supplier = () -> 1;
+        Fn0      fn0      = Fn0.fromSupplier(supplier);
+        assertEquals((Integer) 1, fn0.apply());
+    }
+
+    @Test
+    public void fromCallable() {
+        Callable callable = () -> 1;
+        Fn0      fn0      = Fn0.fromCallable(callable);
+        assertEquals((Integer) 1, fn0.apply());
+    }
+
+    @Test
+    public void toSupplier() {
+        Fn0      fn0      = () -> 1;
+        Supplier supplier = fn0.toSupplier();
+        assertEquals((Integer) 1, supplier.get());
+    }
+
+    @Test
+    public void toCallable() throws Exception {
+        Fn0      fn0      = () -> 1;
+        Callable callable = fn0.toCallable();
+        assertEquals((Integer) 1, callable.call());
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java
index a61b5b752..85db3d418 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java
@@ -16,6 +16,7 @@
 import static com.jnape.palatable.lambda.adt.choice.Choice2.b;
 import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
 import static com.jnape.palatable.lambda.functions.Fn1.fn1;
+import static com.jnape.palatable.lambda.functions.Fn1.fromFunction;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft;
 import static java.util.Arrays.asList;
 import static org.junit.Assert.assertEquals;
@@ -38,9 +39,11 @@ public void profunctorProperties() {
     }
 
     @Test
-    public void staticFactoryMethods() {
-        Function parseInt = Integer::parseInt;
-        assertEquals((Integer) 1, fn1(parseInt).apply("1"));
+    public void staticFactoryMethod() {
+        assertEquals((Integer) 1, Fn1.fn1(Integer::parseInt).apply("1"));
+        Function function = Integer::parseInt;
+        Fn1      fn1      = fromFunction(function);
+        assertEquals((Integer) 1, fn1.apply("1"));
     }
 
     @Test
@@ -52,7 +55,7 @@ public void thunk() {
     @Test
     public void widen() {
         Fn1 addOne = x -> x + 1;
-        assertEquals(just(4), reduceLeft(addOne.widen().toBiFunction(), asList(1, 2, 3)));
+        assertEquals(just(4), reduceLeft(addOne.widen(), asList(1, 2, 3)));
     }
 
     @Test
@@ -80,4 +83,11 @@ public void choose() {
         assertEquals(b(123), add1.choose().apply("123"));
         assertEquals(a("foo"), add1.choose().apply("foo"));
     }
+
+    @Test
+    public void toFunction() {
+        Fn1      add1     = x -> x + 1;
+        Function function = add1.toFunction();
+        assertEquals((Integer) 2, function.apply(1));
+    }
 }
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java
index 89cf70a03..b5c9413b3 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java
@@ -30,12 +30,6 @@ public void uncurries() {
         assertThat(CHECK_LENGTH.uncurry().apply(tuple("abc", 3)), is(true));
     }
 
-    @Test
-    @SuppressWarnings("ConstantConditions")
-    public void composePreservesTypeSpecificity() {
-        assertTrue(CHECK_LENGTH.compose(Object::toString) instanceof Fn2);
-    }
-
     @Test
     public void toBiFunction() {
         BiFunction biFunction = CHECK_LENGTH.toBiFunction();
@@ -44,10 +38,13 @@ public void toBiFunction() {
 
     @Test
     public void fn2() {
-        BiFunction biFunction = String::format;
-        assertEquals("foo bar", Fn2.fn2(biFunction).apply("foo %s", "bar"));
-
         Fn1> curriedFn1 = (x) -> (y) -> String.format(x, y);
         assertEquals("foo bar", Fn2.fn2(curriedFn1).apply("foo %s", "bar"));
     }
+
+    @Test
+    public void fromBiFunction() {
+        BiFunction biFunction = String::format;
+        assertEquals("foo bar", Fn2.fromBiFunction(biFunction).apply("foo %s", "bar"));
+    }
 }
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 d1889525b..8138aaed0 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
@@ -28,7 +28,7 @@ public class FlattenTest {
 
     @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, FiniteIteration.class})
     public Fn1, Iterable> testSubject() {
-        return Flatten.flatten().compose(Map.>map(Collections::singletonList));
+        return Flatten.flatten().contraMap(Map.>map(Collections::singletonList));
     }
 
     @Test
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java
index c266a4bfb..376295e5b 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AllTest.java
@@ -7,8 +7,6 @@
 import org.junit.runner.RunWith;
 import testsupport.traits.EmptyIterableSupport;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.All.all;
@@ -19,7 +17,7 @@
 @RunWith(Traits.class)
 public class AllTest {
 
-    private static final Function EVEN = x -> x.doubleValue() % 2 == 0;
+    private static final Fn1 EVEN = x -> x.doubleValue() % 2 == 0;
 
     @TestTraits({EmptyIterableSupport.class})
     public Fn1, ? extends Boolean> createTestSubject() {
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java
index 73e11e800..9bff92fa4 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java
@@ -4,6 +4,7 @@
 
 import java.util.ArrayList;
 
+import static com.jnape.palatable.lambda.functions.Effect.fromConsumer;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Alter.alter;
 import static java.util.Collections.singletonList;
 import static org.junit.Assert.assertEquals;
@@ -14,7 +15,7 @@ public class AlterTest {
     @Test
     public void altersInput() {
         ArrayList input = new ArrayList<>();
-        assertSame(input, alter(xs -> xs.add("foo"), input).unsafePerformIO());
+        assertSame(input, alter(fromConsumer(xs -> xs.add("foo")), input).unsafePerformIO());
         assertEquals(singletonList("foo"), input);
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java
index ff632730b..ccf0451cd 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AnyTest.java
@@ -7,8 +7,6 @@
 import org.junit.runner.RunWith;
 import testsupport.traits.EmptyIterableSupport;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Any.any;
@@ -19,7 +17,7 @@
 @RunWith(Traits.class)
 public class AnyTest {
 
-    public static final Function EVEN = x -> x % 2 == 0;
+    public static final Fn1 EVEN = x -> x % 2 == 0;
 
     @TestTraits({EmptyIterableSupport.class})
     public Fn1, Boolean> createTestSubject() {
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeByTest.java
index 1995332f2..25b0723eb 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeByTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MagnetizeByTest.java
@@ -11,11 +11,10 @@
 import testsupport.traits.InfiniteIterableSupport;
 import testsupport.traits.Laziness;
 
-import java.util.function.BiFunction;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Last.last;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq;
+import static com.jnape.palatable.lambda.functions.builtin.fn2.GTE.gte;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.MagnetizeBy.magnetizeBy;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Take.take;
 import static java.util.Arrays.asList;
@@ -31,16 +30,15 @@ public class MagnetizeByTest {
 
     @TestTraits({EmptyIterableSupport.class, InfiniteIterableSupport.class, FiniteIteration.class, ImmutableIteration.class, Laziness.class})
     public Fn1, Iterable>> testSubject() {
-        return magnetizeBy(eq().toBiFunction());
+        return magnetizeBy(eq());
     }
 
     @Test
     @SuppressWarnings("unchecked")
     public void magnetizesElementsByPredicateOutcome() {
-        BiFunction lte = (x, y) -> x <= y;
-        assertThat(magnetizeBy(lte, emptyList()), isEmpty());
-        assertThat(magnetizeBy(lte, singletonList(1)), contains(iterates(1)));
-        assertThat(magnetizeBy(lte, asList(1, 2, 3, 2, 2, 3, 2, 1)),
+        assertThat(magnetizeBy(GTE.gte(), emptyList()), isEmpty());
+        assertThat(magnetizeBy(gte(), singletonList(1)), contains(iterates(1)));
+        assertThat(magnetizeBy(gte(), asList(1, 2, 3, 2, 2, 3, 2, 1)),
                    contains(iterates(1, 2, 3),
                             iterates(2, 2, 3),
                             iterates(2),
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2Test.java
deleted file mode 100644
index 81598f331..000000000
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial2Test.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.jnape.palatable.lambda.functions.builtin.fn2;
-
-import org.junit.Test;
-
-import java.util.function.BiFunction;
-
-import static com.jnape.palatable.lambda.functions.builtin.fn2.Partial2.partial2;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
-
-public class Partial2Test {
-
-    @Test
-    public void partiallyAppliesFunction() {
-        BiFunction subtract = (minuend, subtrahend) -> minuend - subtrahend;
-        assertThat(partial2(subtract, 3).apply(2), is(1));
-    }
-}
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3Test.java
deleted file mode 100644
index f939c68eb..000000000
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Partial3Test.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.jnape.palatable.lambda.functions.builtin.fn2;
-
-import com.jnape.palatable.lambda.functions.Fn3;
-import org.junit.Test;
-
-import static com.jnape.palatable.lambda.functions.builtin.fn2.Partial3.partial3;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
-
-public class Partial3Test {
-
-    @Test
-    public void partiallyAppliesFunction() {
-        Fn3 concat = (s1, s2, s3) -> s1 + s2 + s3;
-
-        assertThat(partial3(concat, "foo").apply(" bar", " baz"), is("foo bar baz"));
-    }
-}
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java
index 8aad38db7..ed75f2568 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java
@@ -30,8 +30,8 @@ public class PartitionTest {
 
     @TestTraits({Laziness.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class})
     public Subjects, ?>> createTraitsTestSubject() {
-        return subjects(partition(constantly(a(1))).andThen(Tuple2::_1),
-                        partition(constantly(b(1))).andThen(Tuple2::_2));
+        return subjects(partition(constantly(a(1))).fmap(Tuple2::_1),
+                        partition(constantly(b(1))).fmap(Tuple2::_2));
     }
 
     @Test
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java
index af16097b3..3b0860b22 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java
@@ -8,6 +8,7 @@
 
 import static com.jnape.palatable.lambda.adt.Either.right;
 import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
+import static com.jnape.palatable.lambda.functions.Effect.fromConsumer;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek2.peek2;
 import static org.junit.Assert.assertEquals;
 
@@ -15,17 +16,18 @@ public class Peek2Test {
 
     @Test
     public void peeksAtBothBifunctorValues() {
-        AtomicInteger counter = new AtomicInteger(0);
-        Tuple2 tuple = tuple(1, 2);
-        assertEquals(tuple, peek2(__ -> counter.incrementAndGet(), __ -> counter.incrementAndGet(), tuple));
+        AtomicInteger            counter = new AtomicInteger(0);
+        Tuple2 tuple   = tuple(1, 2);
+        assertEquals(tuple, peek2(fromConsumer(__ -> counter.incrementAndGet()),
+                                  fromConsumer(__ -> counter.incrementAndGet()), tuple));
         assertEquals(2, counter.get());
     }
 
     @Test
     public void followsSameConventionsAsBimap() {
-        AtomicInteger counter = new AtomicInteger(0);
-        Either either = right(1);
-        peek2(__ -> counter.incrementAndGet(), __ -> counter.incrementAndGet(), either);
+        AtomicInteger           counter = new AtomicInteger(0);
+        Either either  = right(1);
+        peek2(fromConsumer(__ -> counter.incrementAndGet()), fromConsumer(__ -> counter.incrementAndGet()), either);
         assertEquals(1, counter.get());
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java
index 337899584..5ab1fba4f 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java
@@ -6,6 +6,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import static com.jnape.palatable.lambda.adt.Maybe.just;
+import static com.jnape.palatable.lambda.functions.Effect.fromConsumer;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek.peek;
 import static org.junit.Assert.assertEquals;
 
@@ -13,9 +14,9 @@ public class PeekTest {
 
     @Test
     public void appliesConsumerToCarrierValue() {
-        AtomicInteger counter = new AtomicInteger(0);
+        AtomicInteger counter     = new AtomicInteger(0);
         Maybe maybeString = just("foo");
-        assertEquals(maybeString, peek(x -> counter.incrementAndGet(), maybeString));
+        assertEquals(maybeString, peek(fromConsumer(x -> counter.incrementAndGet()), maybeString));
         assertEquals(1, counter.get());
     }
 
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java
index e51dfbaa1..b2e65864e 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java
@@ -2,12 +2,11 @@
 
 import com.jnape.palatable.lambda.adt.Either;
 import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.builtin.Compose;
 import com.jnape.palatable.lambda.functor.builtin.Identity;
 import org.junit.Test;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.adt.Either.right;
 import static com.jnape.palatable.lambda.adt.Maybe.just;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
@@ -22,8 +21,8 @@ public class SequenceTest {
 
     @Test
     public void naturality() {
-        Function, Either> t = id -> right(id.runIdentity());
-        Either> traversable = right(new Identity<>(1));
+        Fn1, Either> t           = id -> right(id.runIdentity());
+        Either>        traversable = right(new Identity<>(1));
 
         assertEquals(t.apply(sequence(traversable, Identity::new).fmap(id())),
                      sequence(traversable.fmap(t), Either::right));
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollectionTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollectionTest.java
index 584dd876d..6188c6765 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollectionTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToCollectionTest.java
@@ -3,8 +3,6 @@
 import org.junit.Test;
 
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.function.Supplier;
 
 import static com.jnape.palatable.lambda.functions.builtin.fn2.ToCollection.toCollection;
 import static java.util.Arrays.asList;
@@ -14,7 +12,6 @@ public class ToCollectionTest {
 
     @Test
     public void convertsIterablesToCollectionInstance() {
-        Supplier> listFactory = ArrayList::new;
-        assertEquals(asList(1, 2, 3), toCollection(listFactory, asList(1, 2, 3)));
+        assertEquals(asList(1, 2, 3), toCollection(ArrayList::new, asList(1, 2, 3)));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java
index 1e575879d..f775e60ec 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2Test.java
@@ -2,10 +2,9 @@
 
 import com.jnape.palatable.lambda.adt.Either;
 import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.functions.Fn2;
 import org.junit.Test;
 
-import java.util.function.BiFunction;
-
 import static com.jnape.palatable.lambda.adt.Either.left;
 import static com.jnape.palatable.lambda.adt.Either.right;
 import static com.jnape.palatable.lambda.adt.Maybe.just;
@@ -17,7 +16,7 @@ public class LiftA2Test {
 
     @Test
     public void inference() {
-        BiFunction add = (x, y) -> x + y;
+        Fn2 add = Integer::sum;
 
         Maybe a = liftA2(add, just(1), just(2));
         assertEquals(just(3), a);
@@ -31,7 +30,7 @@ public void inference() {
         Maybe d = liftA2(add, nothing(), nothing());
         assertEquals(nothing(), d);
 
-        Either e = liftA2(add, Either.right(1), right(2));
+        Either e = liftA2(add, Either.right(1), right(2));
         assertEquals(right(3), e);
 
         Either f = liftA2(add, left("error"), right(2));
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWithTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWithTest.java
index ee1408417..034fe1b9a 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWithTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWithTest.java
@@ -10,8 +10,6 @@
 import testsupport.traits.ImmutableIteration;
 import testsupport.traits.Laziness;
 
-import java.util.function.BiFunction;
-
 import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Zip.zip;
 import static com.jnape.palatable.lambda.functions.builtin.fn3.ZipWith.zipWith;
@@ -30,18 +28,16 @@ public Fn1, Iterable> createTestSubject() {
     @Test
     public void zipsTwoIterablesTogetherWithFunction() {
         Iterable oneThroughFive = asList(1, 2, 3, 4, 5);
-        Iterable sixThroughTen = asList(6, 7, 8, 9, 10);
+        Iterable sixThroughTen  = asList(6, 7, 8, 9, 10);
 
-        BiFunction add = (a, b) -> a + b;
-        Iterable sums = ZipWith.zipWith(add, oneThroughFive, sixThroughTen);
+        Iterable sums = zipWith(Integer::sum, oneThroughFive, sixThroughTen);
 
         assertThat(sums, iterates(7, 9, 11, 13, 15));
     }
 
     @Test
-    @SuppressWarnings("unchecked")
     public void zipsAsymmetricallySizedIterables() {
-        Iterable men = asList("Jack", "Sonny");
+        Iterable men   = asList("Jack", "Sonny");
         Iterable women = asList("Jill", "Cher", "Madonna");
 
         Iterable> couples = zip(men, women);
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java
index b37527919..a03305b74 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java
@@ -1,6 +1,7 @@
 package com.jnape.palatable.lambda.functions.builtin.fn4;
 
 import com.jnape.palatable.lambda.functions.Fn1;
+import com.jnape.palatable.lambda.functions.specialized.SideEffect;
 import com.jnape.palatable.lambda.iteration.IterationInterruptedException;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.runners.Traits;
@@ -19,7 +20,7 @@
 import static com.jnape.palatable.lambda.adt.Try.trying;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat;
 import static com.jnape.palatable.lambda.functions.builtin.fn4.RateLimit.rateLimit;
-import static com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable.checked;
+import static com.jnape.palatable.lambda.functions.specialized.SideEffect.sideEffect;
 import static java.time.Clock.systemUTC;
 import static java.time.Duration.ZERO;
 import static java.util.Arrays.asList;
@@ -66,7 +67,7 @@ public void rateLimitingDelayIsInterruptible() throws InterruptedException {
         Thread         testThread = Thread.currentThread();
         CountDownLatch latch      = new CountDownLatch(1);
         new Thread(() -> {
-            trying(checked(latch::await)).orThrow();
+            trying(sideEffect(latch::await)).orThrow();
             testThread.interrupt();
         }) {{
             start();
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 035358e6a..5104aa824 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,11 +1,11 @@
 package com.jnape.palatable.lambda.functions.recursion;
 
 import com.jnape.palatable.lambda.adt.hlist.Tuple2;
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Test;
 
 import java.math.BigInteger;
 import java.util.Map;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
@@ -17,7 +17,8 @@
 
 public class TrampolineTest {
 
-    private static final Function, RecursiveResult, BigInteger>> FACTORIAL =
+    private static final
+    Fn1, RecursiveResult, BigInteger>> FACTORIAL =
             into((x, acc) -> x.compareTo(ONE) > 0 ? recurse(tuple(x.subtract(ONE), x.multiply(acc))) : terminate(acc));
 
     @Test
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/BiPredicateTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/BiPredicateTest.java
index 4a19bbba8..9f472f37c 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/BiPredicateTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/BiPredicateTest.java
@@ -13,44 +13,44 @@ public class BiPredicateTest {
     public void jufBiPredicateTest() {
         BiPredicate equals = String::equals;
 
-        assertTrue(equals.test("abc", "abc"));
-        assertFalse(equals.test("abc", ""));
-        assertFalse(equals.test("", "abc"));
+        assertTrue(equals.apply("abc", "abc"));
+        assertFalse(equals.apply("abc", ""));
+        assertFalse(equals.apply("", "abc"));
     }
 
     @Test
     public void jufBiPredicateAnd() {
-        BiPredicate bothOdd = (x, y) -> x % 2 == 1 && y % 2 == 1;
+        BiPredicate bothOdd     = (x, y) -> x % 2 == 1 && y % 2 == 1;
         BiPredicate greaterThan = (x, y) -> x.compareTo(y) > 0;
 
         BiPredicate conjunction = bothOdd.and(greaterThan);
 
-        assertTrue(conjunction.test(3, 1));
-        assertFalse(conjunction.test(3, 2));
-        assertFalse(conjunction.test(3, 5));
-        assertFalse(conjunction.test(4, 1));
+        assertTrue(conjunction.apply(3, 1));
+        assertFalse(conjunction.apply(3, 2));
+        assertFalse(conjunction.apply(3, 5));
+        assertFalse(conjunction.apply(4, 1));
     }
 
     @Test
     public void jufBiPredicateOr() {
-        BiPredicate bothOdd = (x, y) -> x % 2 == 1 && y % 2 == 1;
+        BiPredicate bothOdd     = (x, y) -> x % 2 == 1 && y % 2 == 1;
         BiPredicate greaterThan = (x, y) -> x.compareTo(y) > 0;
 
         BiPredicate disjunction = bothOdd.or(greaterThan);
 
-        assertTrue(disjunction.test(3, 2));
-        assertTrue(disjunction.test(1, 3));
-        assertFalse(disjunction.test(1, 2));
+        assertTrue(disjunction.apply(3, 2));
+        assertTrue(disjunction.apply(1, 3));
+        assertFalse(disjunction.apply(1, 2));
     }
 
     @Test
     public void jufBiPredicateNegate() {
         BiPredicate equals = String::equals;
 
-        assertTrue(equals.test("a", "a"));
-        assertFalse(equals.test("b", "a"));
-        assertFalse(equals.negate().test("a", "a"));
-        assertTrue(equals.negate().test("b", "a"));
+        assertTrue(equals.apply("a", "a"));
+        assertFalse(equals.apply("b", "a"));
+        assertFalse(equals.negate().apply("a", "a"));
+        assertTrue(equals.negate().apply("b", "a"));
     }
 
     @Test
@@ -58,4 +58,18 @@ public void flip() {
         BiPredicate equals = String::equals;
         assertThat(equals.flip(), instanceOf(BiPredicate.class));
     }
+
+    @Test
+    public void fromPredicate() {
+        java.util.function.BiPredicate jufBiPredicate = Object::equals;
+        BiPredicate                    biPredicate    = BiPredicate.fromBiPredicate(jufBiPredicate);
+        assertTrue(biPredicate.apply("a", "a"));
+    }
+
+    @Test
+    public void toPredicate() {
+        BiPredicate                    biPredicate    = Object::equals;
+        java.util.function.BiPredicate jufBiPredicate = biPredicate.toBiPredicate();
+        assertTrue(jufBiPredicate.test("a", "a"));
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/PredicateTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/PredicateTest.java
index b7c8be809..67ec6fe6a 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/specialized/PredicateTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/PredicateTest.java
@@ -8,47 +8,61 @@
 public class PredicateTest {
 
     @Test
-    public void jufPredicateTest() {
+    public void happyPath() {
         Predicate notEmpty = s -> !(s == null || s.length() == 0);
 
-        assertTrue(notEmpty.test("foo"));
-        assertFalse(notEmpty.test(""));
-        assertFalse(notEmpty.test(null));
+        assertTrue(notEmpty.apply("foo"));
+        assertFalse(notEmpty.apply(""));
+        assertFalse(notEmpty.apply(null));
     }
 
     @Test
-    public void jufPredicateAnd() {
-        Predicate notEmpty = s -> !(s == null || s.length() == 0);
+    public void and() {
+        Predicate notEmpty  = s -> !(s == null || s.length() == 0);
         Predicate lengthGt1 = s -> s.length() > 1;
 
         Predicate conjunction = notEmpty.and(lengthGt1);
 
-        assertTrue(conjunction.test("fo"));
-        assertFalse(conjunction.test("f"));
-        assertFalse(conjunction.test(""));
-        assertFalse(conjunction.test(null));
+        assertTrue(conjunction.apply("fo"));
+        assertFalse(conjunction.apply("f"));
+        assertFalse(conjunction.apply(""));
+        assertFalse(conjunction.apply(null));
     }
 
     @Test
-    public void jufPredicateOr() {
-        Predicate notEmpty = s -> !(s == null || s.length() == 0);
+    public void or() {
+        Predicate notEmpty  = s -> !(s == null || s.length() == 0);
         Predicate lengthGt1 = s -> s != null && s.length() > 1;
 
         Predicate disjunction = lengthGt1.or(notEmpty);
 
-        assertTrue(disjunction.test("fo"));
-        assertTrue(disjunction.test("f"));
-        assertFalse(disjunction.test(""));
-        assertFalse(disjunction.test(null));
+        assertTrue(disjunction.apply("fo"));
+        assertTrue(disjunction.apply("f"));
+        assertFalse(disjunction.apply(""));
+        assertFalse(disjunction.apply(null));
     }
 
     @Test
-    public void jufPredicateNegate() {
+    public void negate() {
         Predicate isTrue = x -> x;
 
-        assertTrue(isTrue.test(true));
-        assertFalse(isTrue.test(false));
-        assertFalse(isTrue.negate().test(true));
-        assertTrue(isTrue.negate().test(false));
+        assertTrue(isTrue.apply(true));
+        assertFalse(isTrue.apply(false));
+        assertFalse(isTrue.negate().apply(true));
+        assertTrue(isTrue.negate().apply(false));
+    }
+
+    @Test
+    public void fromPredicate() {
+        java.util.function.Predicate jufPredicate = String::isEmpty;
+        Predicate                    predicate    = Predicate.fromPredicate(jufPredicate);
+        assertFalse(predicate.apply("123"));
+    }
+
+    @Test
+    public void toPredicate() {
+        Predicate                    predicate    = String::isEmpty;
+        java.util.function.Predicate jufPredicate = predicate.toPredicate();
+        assertFalse(jufPredicate.test("123"));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/SideEffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/SideEffectTest.java
new file mode 100644
index 000000000..64eecfd3b
--- /dev/null
+++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/SideEffectTest.java
@@ -0,0 +1,28 @@
+package com.jnape.palatable.lambda.functions.specialized;
+
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.Assert.assertEquals;
+
+public class SideEffectTest {
+
+    @Test
+    public void fromRunnable() throws Throwable {
+        AtomicInteger counter    = new AtomicInteger(0);
+        Runnable      runnable   = counter::incrementAndGet;
+        SideEffect    sideEffect = SideEffect.fromRunnable(runnable);
+        sideEffect.Ω();
+        assertEquals(1, counter.get());
+    }
+
+    @Test
+    public void toRunnable() {
+        AtomicInteger counter    = new AtomicInteger(0);
+        SideEffect    sideEffect = counter::incrementAndGet;
+        Runnable      runnable   = sideEffect.toRunnable();
+        runnable.run();
+        assertEquals(1, counter.get());
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java b/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java
index bef359ebc..88e027a8a 100644
--- a/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functor/BifunctorTest.java
@@ -1,10 +1,10 @@
 package com.jnape.palatable.lambda.functor;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Test;
 import testsupport.applicatives.InvocationRecordingBifunctor;
 
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
 import static org.hamcrest.CoreMatchers.is;
@@ -14,7 +14,7 @@ public class BifunctorTest {
 
     @Test
     public void biMapLUsesIdentityForRightBiMapFunction() {
-        AtomicReference> rightInvocation = new AtomicReference<>();
+        AtomicReference> rightInvocation = new AtomicReference<>();
         Bifunctor> bifunctor =
                 new InvocationRecordingBifunctor<>(new AtomicReference<>(), rightInvocation);
         bifunctor.biMapL(String::toUpperCase);
@@ -23,7 +23,7 @@ public void biMapLUsesIdentityForRightBiMapFunction() {
 
     @Test
     public void biMapRUsesIdentityForLeftBiMapFunction() {
-        AtomicReference> leftInvocation = new AtomicReference<>();
+        AtomicReference> leftInvocation = new AtomicReference<>();
         Bifunctor> bifunctor =
                 new InvocationRecordingBifunctor<>(leftInvocation, new AtomicReference<>());
         bifunctor.biMapR(String::valueOf);
diff --git a/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java b/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java
index a6650b32a..6d1a34912 100644
--- a/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functor/ProfunctorTest.java
@@ -1,10 +1,10 @@
 package com.jnape.palatable.lambda.functor;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Test;
 import testsupport.applicatives.InvocationRecordingProfunctor;
 
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
 import static org.hamcrest.CoreMatchers.is;
@@ -14,7 +14,7 @@ public class ProfunctorTest {
 
     @Test
     public void diMapLUsesIdentityForRightDiMapFunction() {
-        AtomicReference> rightInvocation = new AtomicReference<>();
+        AtomicReference> rightInvocation = new AtomicReference<>();
         Profunctor> profunctor =
                 new InvocationRecordingProfunctor<>(new AtomicReference<>(), rightInvocation);
         profunctor.diMapL(Object::toString);
@@ -23,7 +23,7 @@ public void diMapLUsesIdentityForRightDiMapFunction() {
 
     @Test
     public void diMapRUsesIdentityForLeftDiMapFunction() {
-        AtomicReference> leftInvocation = new AtomicReference<>();
+        AtomicReference> leftInvocation = new AtomicReference<>();
         Profunctor> profunctor =
                 new InvocationRecordingProfunctor<>(leftInvocation, new AtomicReference<>());
         profunctor.diMapR(String::valueOf);
diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java
index c6bd42b16..7d1659ad2 100644
--- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java
@@ -14,7 +14,6 @@
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.adt.Unit.UNIT;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler;
@@ -66,7 +65,7 @@ public void zipAndDerivativesComposesInParallel() {
             advanceSecond.await();
             return a;
         });
-        IO>> ioF = io(() -> {
+        IO>> ioF = io(() -> {
             advanceFirst.await();
             advanceSecond.countDown();
             return f;
@@ -77,7 +76,7 @@ public void zipAndDerivativesComposesInParallel() {
         assertEquals(f.apply(a), zip.unsafePerformAsyncIO(executor).join());
         assertEquals(f.apply(a), zip.unsafePerformAsyncIO(executor).join());
 
-        IO>> discardL = ioA.discardL(ioF);
+        IO>> discardL = ioA.discardL(ioF);
         assertEquals(f, discardL.unsafePerformAsyncIO().join());
         assertEquals(f, discardL.unsafePerformAsyncIO(executor).join());
 
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java
index cde0c2f1b..9405ee45a 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java
@@ -1,9 +1,9 @@
 package com.jnape.palatable.lambda.iteration;
 
+import com.jnape.palatable.lambda.functions.Fn2;
 import org.junit.Test;
 
 import java.util.NoSuchElementException;
-import java.util.function.BiFunction;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyIterator;
@@ -12,7 +12,7 @@
 
 public class ScanningIteratorTest {
 
-    public static final BiFunction ADD = (x, y) -> x + y;
+    public static final Fn2 ADD = Integer::sum;
 
     @Test
     public void hasNextAtLeastForB() {
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java
index f88705a91..58b351f6f 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java
@@ -1,5 +1,6 @@
 package com.jnape.palatable.lambda.iteration;
 
+import com.jnape.palatable.lambda.functions.Fn2;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -7,7 +8,6 @@
 import org.mockito.runners.MockitoJUnitRunner;
 
 import java.util.Iterator;
-import java.util.function.BiFunction;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
@@ -17,9 +17,9 @@
 @RunWith(MockitoJUnitRunner.class)
 public class ZippingIteratorTest {
 
-    @Mock private BiFunction zipper;
-    @Mock private Iterator                   as;
-    @Mock private Iterator                   bs;
+    @Mock private Fn2 zipper;
+    @Mock private Iterator            as;
+    @Mock private Iterator            bs;
 
     private ZippingIterator zippingIterator;
 
diff --git a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java
index 47b76efdb..46d617e81 100644
--- a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java
@@ -40,9 +40,9 @@ public void simplePrismInference() {
 
     @Test
     public void unPrismExtractsMappings() {
-        Prism                     prism = prism(PARSE_INT.choose(), Object::toString);
-        Function                 is    = prism.unPrism()._1();
-        Function> sis   = prism.unPrism()._2();
+        Prism                prism = prism(PARSE_INT.choose(), Object::toString);
+        Fn1                 is    = prism.unPrism()._1();
+        Fn1> sis   = prism.unPrism()._2();
 
         assertEquals("123", is.apply(123));
         assertEquals(right(123), sis.apply("123"));
diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java
index e76f48e5e..163fa5f20 100644
--- a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java
@@ -1,6 +1,7 @@
 package com.jnape.palatable.lambda.traversable;
 
 import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.framework.Subjects;
 import com.jnape.palatable.traitor.runners.Traits;
@@ -11,8 +12,6 @@
 import testsupport.traits.MonadLaws;
 import testsupport.traits.TraversableLaws;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.adt.Maybe.just;
 import static com.jnape.palatable.lambda.adt.Maybe.nothing;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
@@ -41,8 +40,8 @@ public Subjects> testSubject() {
 
     @Test
     public void zipAppliesCartesianProductOfFunctionsAndValues() {
-        LambdaIterable> fns = wrap(asList(x -> x + 1, x -> x - 1));
-        LambdaIterable xs = wrap(asList(1, 2, 3));
+        LambdaIterable> fns = wrap(asList(x -> x + 1, x -> x - 1));
+        LambdaIterable                                 xs  = wrap(asList(1, 2, 3));
         assertThat(xs.zip(fns).unwrap(), iterates(2, 3, 4, 0, 1, 2));
     }
 
diff --git a/src/test/java/testsupport/EquatableM.java b/src/test/java/testsupport/EquatableM.java
index ad4272ed8..a046e3fa6 100644
--- a/src/test/java/testsupport/EquatableM.java
+++ b/src/test/java/testsupport/EquatableM.java
@@ -1,24 +1,24 @@
 package testsupport;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.monad.Monad;
 
 import java.util.Objects;
-import java.util.function.Function;
 
 public final class EquatableM, A> implements Monad> {
 
-    private final Monad            ma;
-    private final Function equatable;
+    private final Monad       ma;
+    private final Fn1 equatable;
 
-    public EquatableM(Monad ma, Function equatable) {
+    public EquatableM(Monad ma, Fn1 equatable) {
         this.ma = ma;
         this.equatable = equatable;
     }
 
     @Override
-    public  EquatableM flatMap(Function>> f) {
-        return new EquatableM<>(ma.flatMap(f.andThen(x -> x.>coerce().ma)), equatable);
+    public  EquatableM flatMap(Fn1>> f) {
+        return new EquatableM<>(ma.flatMap(f.fmap(x -> x.>coerce().ma)), equatable);
     }
 
     @Override
@@ -27,13 +27,13 @@ public  EquatableM pure(B b) {
     }
 
     @Override
-    public  EquatableM fmap(Function fn) {
+    public  EquatableM fmap(Fn1 fn) {
         return new EquatableM<>(ma.fmap(fn), equatable);
     }
 
     @Override
-    public  EquatableM zip(Applicative, EquatableM> appFn) {
-        return new EquatableM<>(ma.zip(appFn.>>coerce().ma), equatable);
+    public  EquatableM zip(Applicative, EquatableM> appFn) {
+        return new EquatableM<>(ma.zip(appFn.>>coerce().ma), equatable);
     }
 
     @Override
diff --git a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java
index 65ff38cba..8fca9d114 100644
--- a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java
+++ b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java
@@ -1,24 +1,25 @@
 package testsupport.applicatives;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.Bifunctor;
 
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Function;
 
 public final class InvocationRecordingBifunctor implements Bifunctor> {
-    private final AtomicReference> leftFn;
-    private final AtomicReference> rightFn;
+    private final AtomicReference> leftFn;
+    private final AtomicReference> rightFn;
 
-    public InvocationRecordingBifunctor(AtomicReference> leftFn,
-                                        AtomicReference> rightFn) {
+    public InvocationRecordingBifunctor(AtomicReference> leftFn,
+                                        AtomicReference> rightFn) {
         this.leftFn = leftFn;
         this.rightFn = rightFn;
     }
 
     @Override
     @SuppressWarnings("unchecked")
-    public  InvocationRecordingBifunctor biMap(Function lFn,
-                                                           Function rFn) {
+    public  InvocationRecordingBifunctor biMap(Fn1 lFn,
+                                                           Fn1 rFn) {
         leftFn.set(lFn);
         rightFn.set(rFn);
         return (InvocationRecordingBifunctor) this;
diff --git a/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java b/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java
index 28c34ee0f..403dee83c 100644
--- a/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java
+++ b/src/test/java/testsupport/applicatives/InvocationRecordingProfunctor.java
@@ -1,24 +1,24 @@
 package testsupport.applicatives;
 
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.Profunctor;
 
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Function;
 
 public final class InvocationRecordingProfunctor implements Profunctor> {
-    private final AtomicReference> leftFn;
-    private final AtomicReference> rightFn;
+    private final AtomicReference> leftFn;
+    private final AtomicReference> rightFn;
 
-    public InvocationRecordingProfunctor(AtomicReference> leftFn,
-                                         AtomicReference> rightFn) {
+    public InvocationRecordingProfunctor(AtomicReference> leftFn,
+                                         AtomicReference> rightFn) {
         this.leftFn = leftFn;
         this.rightFn = rightFn;
     }
 
     @Override
     @SuppressWarnings("unchecked")
-    public  InvocationRecordingProfunctor diMap(Function lFn,
-                                                            Function rFn) {
+    public  InvocationRecordingProfunctor diMap(Fn1 lFn,
+                                                            Fn1 rFn) {
         leftFn.set(lFn);
         rightFn.set(rFn);
         return (InvocationRecordingProfunctor) this;
diff --git a/src/test/java/testsupport/functions/ExplainFold.java b/src/test/java/testsupport/functions/ExplainFold.java
index a168674e3..488b05476 100644
--- a/src/test/java/testsupport/functions/ExplainFold.java
+++ b/src/test/java/testsupport/functions/ExplainFold.java
@@ -1,12 +1,14 @@
 package testsupport.functions;
 
+import com.jnape.palatable.lambda.functions.Fn2;
+
 import java.util.function.BiFunction;
 
 import static java.lang.String.format;
 
 public class ExplainFold {
 
-    public static BiFunction explainFold() {
+    public static Fn2 explainFold() {
         return (acc, x) -> format("(%s + %s)", acc, x);
     }
 }
diff --git a/src/test/java/testsupport/matchers/LeftMatcher.java b/src/test/java/testsupport/matchers/LeftMatcher.java
index 7982965a8..7ccb74737 100644
--- a/src/test/java/testsupport/matchers/LeftMatcher.java
+++ b/src/test/java/testsupport/matchers/LeftMatcher.java
@@ -5,6 +5,7 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 
+import static com.jnape.palatable.lambda.functions.Effect.fromConsumer;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
 
 public final class LeftMatcher extends TypeSafeMatcher> {
@@ -29,11 +30,11 @@ public void describeTo(Description description) {
     @Override
     protected void describeMismatchSafely(Either item, Description mismatchDescription) {
         mismatchDescription.appendText("was ");
-        item.peek(l -> {
+        item.peek(fromConsumer(l -> {
                       mismatchDescription.appendText("Left value of ");
                       lMatcher.describeMismatch(l, mismatchDescription);
-                  },
-                  r -> mismatchDescription.appendValue(item));
+                  }),
+                  fromConsumer(r -> mismatchDescription.appendValue(item)));
     }
 
     public static  LeftMatcher isLeftThat(Matcher lMatcher) {
diff --git a/src/test/java/testsupport/matchers/RightMatcher.java b/src/test/java/testsupport/matchers/RightMatcher.java
index 08965bf2f..8e4f15c36 100644
--- a/src/test/java/testsupport/matchers/RightMatcher.java
+++ b/src/test/java/testsupport/matchers/RightMatcher.java
@@ -5,6 +5,7 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 
+import static com.jnape.palatable.lambda.functions.Effect.fromConsumer;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
 
 public final class RightMatcher extends TypeSafeMatcher> {
@@ -29,11 +30,11 @@ public void describeTo(Description description) {
     @Override
     protected void describeMismatchSafely(Either item, Description mismatchDescription) {
         mismatchDescription.appendText("was ");
-        item.peek(l -> mismatchDescription.appendValue(item),
-                  r -> {
+        item.peek(fromConsumer(l -> mismatchDescription.appendValue(item)),
+                  fromConsumer(r -> {
                       mismatchDescription.appendText("Right value of ");
                       rMatcher.describeMismatch(r, mismatchDescription);
-                  });
+                  }));
     }
 
     public static  RightMatcher isRightThat(Matcher rMatcher) {
diff --git a/src/test/java/testsupport/traits/ApplicativeLaws.java b/src/test/java/testsupport/traits/ApplicativeLaws.java
index 11397da5a..5b8b0b713 100644
--- a/src/test/java/testsupport/traits/ApplicativeLaws.java
+++ b/src/test/java/testsupport/traits/ApplicativeLaws.java
@@ -1,6 +1,7 @@
 package testsupport.traits;
 
 import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.monoid.builtin.Present;
 import com.jnape.palatable.traitor.traits.Trait;
@@ -14,14 +15,13 @@
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
 import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy;
 import static java.util.Arrays.asList;
-import static java.util.function.Function.identity;
 
 public class ApplicativeLaws> implements Trait> {
 
     @Override
     public void test(Applicative applicative) {
         Present.present((x, y) -> x + "\n\t - " + y)
-                ., Maybe>>foldMap(
+                ., Maybe>>foldMap(
                         f -> f.apply(applicative),
                         asList(this::testIdentity,
                                this::testComposition,
@@ -37,44 +37,45 @@ public void test(Applicative applicative) {
     }
 
     private Maybe testIdentity(Applicative applicative) {
-        Applicative v = applicative.pure(1);
-        Applicative, App> pureId = v.pure(identity());
+        Applicative                                 v      = applicative.pure(1);
+        Applicative, App> pureId = v.pure(id());
         return v.zip(pureId).equals(v)
                ? nothing()
                : just("identity (v.zip(pureId).equals(v))");
     }
 
     private Maybe testComposition(Applicative applicative) {
-        Random random = new Random();
-        Integer firstInt = random.nextInt(100);
+        Random  random    = new Random();
+        Integer firstInt  = random.nextInt(100);
         Integer secondInt = random.nextInt(100);
 
-        Function, ? extends Function, ? extends Function>> compose = x -> x::compose;
-        Applicative, App> u = applicative.pure(x -> x + firstInt);
-        Applicative, App> v = applicative.pure(x -> x + secondInt);
-        Applicative w = applicative.pure("result: ");
+        Fn1,
+                Fn1,
+                        Fn1>> compose = x -> x::contraMap;
+        Applicative, App> u = applicative.pure(x -> x + firstInt);
+        Applicative, App> v = applicative.pure(x -> x + secondInt);
+        Applicative                                w = applicative.pure("result: ");
 
-        Applicative, ? extends Function, ? extends Function>>, App> pureCompose = u.pure(compose);
-        return w.zip(v.zip(u.zip(pureCompose))).equals(w.zip(v).zip(u))
+        return w.zip(v.zip(u.zip(u.pure(compose)))).equals(w.zip(v).zip(u))
                ? nothing()
                : just("composition (w.zip(v.zip(u.zip(pureCompose))).equals((w.zip(v)).zip(u)))");
     }
 
     private Maybe testHomomorphism(Applicative applicative) {
-        Function f = x -> x + 1;
-        int x = 1;
+        Fn1 f = x -> x + 1;
+        int                   x = 1;
 
-        Applicative pureX = applicative.pure(x);
-        Applicative, App> pureF = applicative.pure(f);
-        Applicative pureFx = applicative.pure(f.apply(x));
+        Applicative                                 pureX  = applicative.pure(x);
+        Applicative, App> pureF  = applicative.pure(f);
+        Applicative                                 pureFx = applicative.pure(f.apply(x));
         return pureX.zip(pureF).equals(pureFx)
                ? nothing()
                : just("homomorphism (pureX.zip(pureF).equals(pureFx))");
     }
 
     private Maybe testInterchange(Applicative applicative) {
-        Applicative, App> u = applicative.pure(x -> x + 1);
-        int y = 1;
+        Applicative, App> u = applicative.pure(x -> x + 1);
+        int                                                       y = 1;
 
         Applicative pureY = applicative.pure(y);
         return pureY.zip(u).equals(u.zip(applicative.pure(f -> f.apply(y))))
@@ -86,7 +87,7 @@ private Maybe testDiscardL(Applicative applicative) {
         Applicative u = applicative.pure("u");
         Applicative v = applicative.pure("v");
 
-        return u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(identity())))))
+        return u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(id())))))
                ? nothing()
                : just("discardL u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(identity())))))");
     }
diff --git a/src/test/java/testsupport/traits/BifunctorLaws.java b/src/test/java/testsupport/traits/BifunctorLaws.java
index 55278590e..780519c17 100644
--- a/src/test/java/testsupport/traits/BifunctorLaws.java
+++ b/src/test/java/testsupport/traits/BifunctorLaws.java
@@ -1,12 +1,11 @@
 package testsupport.traits;
 
 import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.Bifunctor;
 import com.jnape.palatable.lambda.monoid.builtin.Present;
 import com.jnape.palatable.traitor.traits.Trait;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.adt.Maybe.just;
 import static com.jnape.palatable.lambda.adt.Maybe.nothing;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
@@ -17,7 +16,7 @@ public class BifunctorLaws> implements Trait bifunctor) {
         Present.present((x, y) -> x + "\n\t - " + y)
-                ., Maybe>>foldMap(
+                ., Maybe>>foldMap(
                         f -> f.apply(bifunctor),
                         asList(this::testLeftIdentity,
                                this::testRightIdentity,
diff --git a/src/test/java/testsupport/traits/FunctorLaws.java b/src/test/java/testsupport/traits/FunctorLaws.java
index dbe96c6e5..c2bb1791c 100644
--- a/src/test/java/testsupport/traits/FunctorLaws.java
+++ b/src/test/java/testsupport/traits/FunctorLaws.java
@@ -1,6 +1,7 @@
 package testsupport.traits;
 
 import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.Functor;
 import com.jnape.palatable.lambda.monoid.builtin.Present;
 import com.jnape.palatable.traitor.traits.Trait;
@@ -10,15 +11,15 @@
 import static com.jnape.palatable.lambda.adt.Maybe.just;
 import static com.jnape.palatable.lambda.adt.Maybe.nothing;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
+import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
 import static java.util.Arrays.asList;
-import static java.util.function.Function.identity;
 
 public class FunctorLaws> implements Trait> {
 
     @Override
     public void test(Functor f) {
         Present.present((x, y) -> x + "\n\t - " + y)
-                ., Maybe>>foldMap(
+                ., Maybe>>foldMap(
                         fn -> fn.apply(f),
                         asList(this::testIdentity,
                                this::testComposition))
@@ -28,17 +29,17 @@ public void test(Functor f) {
     }
 
     private Maybe testIdentity(Functor f) {
-        return f.fmap(identity()).equals(f)
+        return f.fmap(id()).equals(f)
                ? nothing()
                : just("identity (f.fmap(identity()).equals(f))");
     }
 
     private Maybe testComposition(Functor functor) {
-        Functor subject = functor.fmap(constantly(1));
-        Function f = x -> x * 3;
-        Function g = x -> x - 2;
-        return subject.fmap(f.compose(g)).equals(subject.fmap(g).fmap(f))
+        Functor   subject = functor.fmap(constantly(1));
+        Fn1 f       = x -> x * 3;
+        Fn1 g       = x -> x - 2;
+        return subject.fmap(f.contraMap(g)).equals(subject.fmap(g).fmap(f))
                ? nothing()
-               : just("composition (functor.fmap(f.compose(g)).equals(functor.fmap(g).fmap(f)))");
+               : just("composition (functor.fmap(f.contraMap(g)).equals(functor.fmap(g).fmap(f)))");
     }
 }
diff --git a/src/test/java/testsupport/traits/MonadLaws.java b/src/test/java/testsupport/traits/MonadLaws.java
index 98738eb57..5ea31ac98 100644
--- a/src/test/java/testsupport/traits/MonadLaws.java
+++ b/src/test/java/testsupport/traits/MonadLaws.java
@@ -21,7 +21,7 @@ public class MonadLaws> implements Trait> {
     @Override
     public void test(Monad m) {
         Present.present((x, y) -> x + "\n\t - " + y)
-                ., Maybe>>foldMap(f -> f.apply(m), asList(
+                ., Maybe>>foldMap(f -> f.apply(m), asList(
                         this::testLeftIdentity,
                         this::testRightIdentity,
                         this::testAssociativity,
@@ -32,8 +32,8 @@ public void test(Monad m) {
     }
 
     private Maybe testLeftIdentity(Monad m) {
-        Object a = new Object();
-        Fn1> fn = id().andThen(m::pure);
+        Object                        a  = new Object();
+        Fn1> fn = id().fmap(m::pure);
         return m.pure(a).flatMap(fn).equals(fn.apply(a))
                ? nothing()
                : just("left identity (m.pure(a).flatMap(fn).equals(fn.apply(a)))");
@@ -47,15 +47,15 @@ private Maybe testRightIdentity(Monad m) {
 
     private Maybe testAssociativity(Monad m) {
         Fn1> f = constantly(m.pure(new Object()));
-        Function> g = constantly(m.pure(new Object()));
+        Fn1> g = constantly(m.pure(new Object()));
         return m.flatMap(f).flatMap(g).equals(m.flatMap(a -> f.apply(a).flatMap(g)))
                ? nothing()
                : just("associativity: (m.flatMap(f).flatMap(g).equals(m.flatMap(a -> f.apply(a).flatMap(g))))");
     }
 
     private Maybe testJoin(Monad m) {
-        Monad, M> mma = m.pure(m.fmap(upcast()));
-        boolean equals = mma.flatMap(id()).equals(join(mma));
+        Monad, M> mma    = m.pure(m.fmap(upcast()));
+        boolean                    equals = mma.flatMap(id()).equals(join(mma));
         return equals
                ? nothing()
                : just("join: (m.pure(m).flatMap(id())).equals(Monad.join(m.pure(m)))");
diff --git a/src/test/java/testsupport/traits/TraversableLaws.java b/src/test/java/testsupport/traits/TraversableLaws.java
index a9095fd97..3939c3c3d 100644
--- a/src/test/java/testsupport/traits/TraversableLaws.java
+++ b/src/test/java/testsupport/traits/TraversableLaws.java
@@ -2,6 +2,7 @@
 
 import com.jnape.palatable.lambda.adt.Either;
 import com.jnape.palatable.lambda.adt.Maybe;
+import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.functor.builtin.Compose;
 import com.jnape.palatable.lambda.functor.builtin.Identity;
@@ -23,29 +24,32 @@ public class TraversableLaws> implements Trait
     @Override
     public void test(Traversable traversable) {
         Present.present((x, y) -> x + "\n\t - " + y)
-                ., Maybe>>foldMap(
+                ., Maybe>>foldMap(
                         f -> f.apply(traversable),
                         asList(this::testNaturality,
                                this::testIdentity,
                                this::testComposition)
                 )
                 .peek(s -> {
-                    throw new AssertionError("The following Traversable laws did not hold for instance of " + traversable.getClass() + ": \n\t - " + s);
+                    throw new AssertionError("The following Traversable laws did not hold for instance of "
+                                                     + traversable.getClass() + ": \n\t - " + s);
                 });
     }
 
     private Maybe testNaturality(Traversable trav) {
-        Function> f = Identity::new;
-        Function, Either> t = id -> right(id.runIdentity());
+        Fn1>                 f = Identity::new;
+        Fn1, Either> t = id -> right(id.runIdentity());
 
-        Function, Applicative, Identity>> pureFn = x -> new Identity<>(x);
-        Function, Applicative, Either>> pureFn2 = x -> right(x);
+        Fn1, Applicative, Identity>> pureFn =
+                x -> new Identity<>(x);
+        Fn1, Applicative, Either>> pureFn2 =
+                x -> right(x);
 
         return t.apply(trav.traverse(f, pureFn).fmap(id()).coerce())
-                       .equals(trav.traverse(t.compose(f), pureFn2).fmap(id()).coerce())
+                       .equals(trav.traverse(t.contraMap(f), pureFn2).fmap(id()).coerce())
                ? nothing()
                : just("naturality (t.apply(trav.traverse(f, pureFn).fmap(id()).coerce())\n" +
-                              "                .equals(trav.traverse(t.compose(f), pureFn2).fmap(id()).coerce()))");
+                              "                .equals(trav.traverse(t.contraMap(f), pureFn2).fmap(id()).coerce()))");
     }
 
     private Maybe testIdentity(Traversable trav) {
@@ -55,13 +59,13 @@ private Maybe testIdentity(Traversable trav) {
     }
 
     private Maybe testComposition(Traversable trav) {
-        Function> f = Identity::new;
-        Function>> g = x -> new Identity<>(x);
+        Fn1>                 f = Identity::new;
+        Fn1>> g = x -> new Identity<>(x);
 
-        return trav.traverse(f.andThen(x -> x.fmap(g)).andThen(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x))))
+        return trav.traverse(f.fmap(x -> x.fmap(g)).fmap(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x))))
                        .equals(new Compose<>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x)))))
                ? nothing()
-               : just("compose (trav.traverse(f.andThen(x -> x.fmap(g)).andThen(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x))))\n" +
+               : just("compose (trav.traverse(f.fmap(x -> x.fmap(g)).fmap(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x))))\n" +
                               "                .equals(new Compose>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x))))))");
     }
 }

From 70f4a1073cedccdb55baf2c1b4b8f0fa1275a81e Mon Sep 17 00:00:00 2001
From: jnape 
Date: Thu, 9 May 2019 20:12:00 -0500
Subject: [PATCH 147/348] Moving all internal classes to internal package

---
 src/main/java/com/jnape/palatable/lambda/adt/Try.java        | 4 ++--
 .../java/com/jnape/palatable/lambda/functions/Effect.java    | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn1.java  | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn2.java  | 3 +--
 src/main/java/com/jnape/palatable/lambda/functions/Fn3.java  | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn4.java  | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn5.java  | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn6.java  | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn7.java  | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn8.java  | 2 +-
 .../jnape/palatable/lambda/functions/builtin/fn1/Cycle.java  | 2 +-
 .../palatable/lambda/functions/builtin/fn1/Distinct.java     | 2 +-
 .../palatable/lambda/functions/builtin/fn1/Flatten.java      | 2 +-
 .../jnape/palatable/lambda/functions/builtin/fn1/Init.java   | 2 +-
 .../jnape/palatable/lambda/functions/builtin/fn1/Repeat.java | 2 +-
 .../palatable/lambda/functions/builtin/fn1/Reverse.java      | 2 +-
 .../lambda/functions/builtin/fn2/CartesianProduct.java       | 2 +-
 .../jnape/palatable/lambda/functions/builtin/fn2/Cons.java   | 2 +-
 .../jnape/palatable/lambda/functions/builtin/fn2/Drop.java   | 2 +-
 .../palatable/lambda/functions/builtin/fn2/DropWhile.java    | 2 +-
 .../jnape/palatable/lambda/functions/builtin/fn2/Filter.java | 2 +-
 .../palatable/lambda/functions/builtin/fn2/InGroupsOf.java   | 2 +-
 .../jnape/palatable/lambda/functions/builtin/fn2/Map.java    | 2 +-
 .../palatable/lambda/functions/builtin/fn2/PrependAll.java   | 2 +-
 .../jnape/palatable/lambda/functions/builtin/fn2/Snoc.java   | 2 +-
 .../jnape/palatable/lambda/functions/builtin/fn2/Take.java   | 2 +-
 .../palatable/lambda/functions/builtin/fn2/TakeWhile.java    | 2 +-
 .../palatable/lambda/functions/builtin/fn2/Unfoldr.java      | 2 +-
 .../palatable/lambda/functions/builtin/fn3/ScanLeft.java     | 2 +-
 .../palatable/lambda/functions/builtin/fn3/ZipWith.java      | 4 +---
 .../palatable/lambda/functions/builtin/fn4/RateLimit.java    | 4 ++--
 .../lambda/functions/specialized/BiMonoidFactory.java        | 2 +-
 .../lambda/functions/specialized/MonoidFactory.java          | 2 +-
 .../jnape/palatable/lambda/functions/specialized/Pure.java   | 2 +-
 .../palatable/lambda/functions/specialized/SideEffect.java   | 2 +-
 .../{functions/specialized/checked => internal}/Runtime.java | 2 +-
 .../{ => internal}/iteration/CombinatorialIterator.java      | 2 +-
 .../{ => internal}/iteration/ConcatenatingIterable.java      | 2 +-
 .../lambda/{ => internal}/iteration/ConsingIterator.java     | 2 +-
 .../lambda/{ => internal}/iteration/CyclicIterable.java      | 2 +-
 .../lambda/{ => internal}/iteration/CyclicIterator.java      | 2 +-
 .../lambda/{ => internal}/iteration/DistinctIterable.java    | 2 +-
 .../lambda/{ => internal}/iteration/DroppingIterable.java    | 2 +-
 .../lambda/{ => internal}/iteration/DroppingIterator.java    | 2 +-
 .../lambda/{ => internal}/iteration/FilteringIterable.java   | 2 +-
 .../lambda/{ => internal}/iteration/FilteringIterator.java   | 2 +-
 .../lambda/{ => internal}/iteration/FlatteningIterator.java  | 2 +-
 .../lambda/{ => internal}/iteration/GroupingIterator.java    | 2 +-
 .../lambda/{ => internal}/iteration/ImmutableIterator.java   | 2 +-
 .../lambda/{ => internal}/iteration/ImmutableQueue.java      | 2 +-
 .../lambda/{ => internal}/iteration/ImmutableStack.java      | 2 +-
 .../lambda/{ => internal}/iteration/InfiniteIterator.java    | 2 +-
 .../lambda/{ => internal}/iteration/InitIterator.java        | 2 +-
 .../iteration/IterationInterruptedException.java             | 2 +-
 .../lambda/{ => internal}/iteration/MappingIterable.java     | 2 +-
 .../lambda/{ => internal}/iteration/MappingIterator.java     | 2 +-
 .../{ => internal}/iteration/PredicatedDroppingIterable.java | 2 +-
 .../{ => internal}/iteration/PredicatedDroppingIterator.java | 2 +-
 .../{ => internal}/iteration/PredicatedTakingIterable.java   | 2 +-
 .../{ => internal}/iteration/PredicatedTakingIterator.java   | 2 +-
 .../lambda/{ => internal}/iteration/PrependingIterator.java  | 2 +-
 .../{ => internal}/iteration/RateLimitingIterable.java       | 3 +--
 .../{ => internal}/iteration/RateLimitingIterator.java       | 2 +-
 .../lambda/{ => internal}/iteration/RepetitiousIterator.java | 2 +-
 .../lambda/{ => internal}/iteration/ReversingIterable.java   | 2 +-
 .../lambda/{ => internal}/iteration/ReversingIterator.java   | 2 +-
 .../lambda/{ => internal}/iteration/RewindableIterator.java  | 2 +-
 .../lambda/{ => internal}/iteration/ScanningIterator.java    | 2 +-
 .../lambda/{ => internal}/iteration/SnocIterable.java        | 2 +-
 .../lambda/{ => internal}/iteration/SnocIterator.java        | 2 +-
 .../lambda/{ => internal}/iteration/TakingIterable.java      | 2 +-
 .../lambda/{ => internal}/iteration/TakingIterator.java      | 2 +-
 .../lambda/{ => internal}/iteration/UnfoldingIterator.java   | 2 +-
 .../lambda/{ => internal}/iteration/UnioningIterable.java    | 2 +-
 .../lambda/{ => internal}/iteration/ZippingIterator.java     | 2 +-
 .../com/jnape/palatable/lambda/monoid/builtin/Concat.java    | 2 +-
 .../com/jnape/palatable/lambda/monoid/builtin/Union.java     | 2 +-
 .../lambda/functions/builtin/fn4/RateLimitTest.java          | 3 +--
 .../{ => internal}/iteration/CombinatorialIteratorTest.java  | 2 +-
 .../{ => internal}/iteration/ConcatenatingIterableTest.java  | 2 +-
 .../lambda/{ => internal}/iteration/ConsingIteratorTest.java | 2 +-
 .../lambda/{ => internal}/iteration/CyclicIterableTest.java  | 2 +-
 .../lambda/{ => internal}/iteration/CyclicIteratorTest.java  | 2 +-
 .../{ => internal}/iteration/DistinctIterableTest.java       | 2 +-
 .../{ => internal}/iteration/DroppingIterableTest.java       | 2 +-
 .../{ => internal}/iteration/DroppingIteratorTest.java       | 2 +-
 .../{ => internal}/iteration/FilteringIterableTest.java      | 2 +-
 .../{ => internal}/iteration/FilteringIteratorTest.java      | 2 +-
 .../{ => internal}/iteration/FlatteningIteratorTest.java     | 2 +-
 .../{ => internal}/iteration/GroupingIteratorTest.java       | 2 +-
 .../{ => internal}/iteration/ImmutableIteratorTest.java      | 2 +-
 .../{ => internal}/iteration/InfiniteIteratorTest.java       | 2 +-
 .../lambda/{ => internal}/iteration/InitIteratorTest.java    | 2 +-
 .../lambda/{ => internal}/iteration/MappingIterableTest.java | 2 +-
 .../lambda/{ => internal}/iteration/MappingIteratorTest.java | 2 +-
 .../iteration/PredicatedDroppingIterableTest.java            | 2 +-
 .../iteration/PredicatedDroppingIteratorTest.java            | 2 +-
 .../iteration/PredicatedTakingIterableTest.java              | 2 +-
 .../iteration/PredicatedTakingIteratorTest.java              | 2 +-
 .../{ => internal}/iteration/PrependingIteratorTest.java     | 2 +-
 .../{ => internal}/iteration/RepetitiousIteratorTest.java    | 2 +-
 .../{ => internal}/iteration/ReversingIterableTest.java      | 2 +-
 .../{ => internal}/iteration/ReversingIteratorTest.java      | 2 +-
 .../{ => internal}/iteration/RewindableIteratorTest.java     | 2 +-
 .../{ => internal}/iteration/ScanningIteratorTest.java       | 2 +-
 .../lambda/{ => internal}/iteration/SnocIterableTest.java    | 2 +-
 .../lambda/{ => internal}/iteration/SnocIteratorTest.java    | 2 +-
 .../lambda/{ => internal}/iteration/TakingIterableTest.java  | 2 +-
 .../lambda/{ => internal}/iteration/TakingIteratorTest.java  | 5 +++--
 .../{ => internal}/iteration/UnfoldingIteratorTest.java      | 2 +-
 .../{ => internal}/iteration/UnioningIterableTest.java       | 2 +-
 .../lambda/{ => internal}/iteration/ZippingIteratorTest.java | 2 +-
 112 files changed, 116 insertions(+), 120 deletions(-)
 rename src/main/java/com/jnape/palatable/lambda/{functions/specialized/checked => internal}/Runtime.java (76%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/CombinatorialIterator.java (96%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/ConcatenatingIterable.java (94%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/ConsingIterator.java (95%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/CyclicIterable.java (88%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/CyclicIterator.java (94%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/DistinctIterable.java (91%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/DroppingIterable.java (91%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/DroppingIterator.java (93%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/FilteringIterable.java (95%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/FilteringIterator.java (95%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/FlatteningIterator.java (92%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/GroupingIterator.java (92%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/ImmutableIterator.java (81%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/ImmutableQueue.java (98%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/ImmutableStack.java (97%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/InfiniteIterator.java (73%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/InitIterator.java (92%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/IterationInterruptedException.java (88%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/MappingIterable.java (95%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/MappingIterator.java (91%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/PredicatedDroppingIterable.java (95%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/PredicatedDroppingIterator.java (95%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/PredicatedTakingIterable.java (95%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/PredicatedTakingIterator.java (95%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/PrependingIterator.java (93%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/RateLimitingIterable.java (92%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/RateLimitingIterator.java (98%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/RepetitiousIterator.java (81%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/ReversingIterable.java (92%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/ReversingIterator.java (94%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/RewindableIterator.java (96%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/ScanningIterator.java (94%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/SnocIterable.java (93%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/SnocIterator.java (91%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/TakingIterable.java (91%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/TakingIterator.java (92%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/UnfoldingIterator.java (95%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/UnioningIterable.java (92%)
 rename src/main/java/com/jnape/palatable/lambda/{ => internal}/iteration/ZippingIterator.java (93%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/CombinatorialIteratorTest.java (97%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/ConcatenatingIterableTest.java (94%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/ConsingIteratorTest.java (97%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/CyclicIterableTest.java (88%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/CyclicIteratorTest.java (92%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/DistinctIterableTest.java (88%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/DroppingIterableTest.java (88%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/DroppingIteratorTest.java (95%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/FilteringIterableTest.java (91%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/FilteringIteratorTest.java (95%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/FlatteningIteratorTest.java (96%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/GroupingIteratorTest.java (96%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/ImmutableIteratorTest.java (92%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/InfiniteIteratorTest.java (93%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/InitIteratorTest.java (94%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/MappingIterableTest.java (91%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/MappingIteratorTest.java (91%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/PredicatedDroppingIterableTest.java (91%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/PredicatedDroppingIteratorTest.java (97%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/PredicatedTakingIterableTest.java (91%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/PredicatedTakingIteratorTest.java (98%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/PrependingIteratorTest.java (96%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/RepetitiousIteratorTest.java (93%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/ReversingIterableTest.java (90%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/ReversingIteratorTest.java (97%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/RewindableIteratorTest.java (97%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/ScanningIteratorTest.java (96%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/SnocIterableTest.java (89%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/SnocIteratorTest.java (95%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/TakingIterableTest.java (90%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/TakingIteratorTest.java (92%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/UnfoldingIteratorTest.java (96%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/UnioningIterableTest.java (94%)
 rename src/test/java/com/jnape/palatable/lambda/{ => internal}/iteration/ZippingIteratorTest.java (96%)

diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java
index 3aeacead1..e89854b39 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java
@@ -4,7 +4,6 @@
 import com.jnape.palatable.lambda.functions.Fn0;
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.specialized.SideEffect;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.functor.builtin.Lazy;
 import com.jnape.palatable.lambda.io.IO;
@@ -13,6 +12,7 @@
 
 import java.util.Objects;
 
+import static com.jnape.palatable.lambda.internal.Runtime.throwChecked;
 import static com.jnape.palatable.lambda.adt.Maybe.nothing;
 import static com.jnape.palatable.lambda.adt.Unit.UNIT;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
@@ -354,7 +354,7 @@ private Failure(Throwable t) {
 
         @Override
         public A orThrow() {
-            throw Runtime.throwChecked(t);
+            throw throwChecked(t);
         }
 
         @Override
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java
index 8516c19c8..4fdfba136 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.adt.Unit;
 import com.jnape.palatable.lambda.functions.specialized.SideEffect;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.io.IO;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java
index 49c69d2de..9df14981a 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java
@@ -3,7 +3,7 @@
 import com.jnape.palatable.lambda.adt.Either;
 import com.jnape.palatable.lambda.adt.choice.Choice2;
 import com.jnape.palatable.lambda.adt.hlist.Tuple2;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.functor.Cartesian;
 import com.jnape.palatable.lambda.functor.Cocartesian;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java
index 7620ea9a7..977082ed2 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java
@@ -1,11 +1,10 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 
 import java.util.function.BiFunction;
-import java.util.function.Function;
 
 import static com.jnape.palatable.lambda.functions.Fn3.fn3;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java
index 9003aa0ac..a225f7e3a 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 
 import static com.jnape.palatable.lambda.functions.Fn4.fn4;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java
index aa49270d5..e43dcda17 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 
 import static com.jnape.palatable.lambda.functions.Fn5.fn5;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java
index b0c0acfba..55364e8bb 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 
 import static com.jnape.palatable.lambda.functions.Fn6.fn6;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java
index 0f06798c6..5998bc9aa 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 
 import static com.jnape.palatable.lambda.functions.Fn7.fn7;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java
index 70b7ba3f6..87a3f8704 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 
 import static com.jnape.palatable.lambda.functions.Fn8.fn8;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java
index 040fa4346..4ead63674 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 
 /**
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java
index 2c39f4391..a5aaaa25b 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Cycle.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions.builtin.fn1;
 
 import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.iteration.CyclicIterable;
+import com.jnape.palatable.lambda.internal.iteration.CyclicIterable;
 
 import static java.util.Arrays.asList;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java
index aab8dfdb3..30b97dec4 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Distinct.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions.builtin.fn1;
 
 import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.iteration.DistinctIterable;
+import com.jnape.palatable.lambda.internal.iteration.DistinctIterable;
 
 /**
  * Return an {@link Iterable} of the distinct values from the given input {@link Iterable}.
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java
index c1f8c0f6d..812452965 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Flatten.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions.builtin.fn1;
 
 import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.iteration.FlatteningIterator;
+import com.jnape.palatable.lambda.internal.iteration.FlatteningIterator;
 
 /**
  * Given a nested {@link Iterable} of {@link Iterable}s, return a lazily flattening {@link Iterable}
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java
index bb75ad1b1..66cea88bf 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Init.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions.builtin.fn1;
 
 import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.iteration.InitIterator;
+import com.jnape.palatable.lambda.internal.iteration.InitIterator;
 
 /**
  * Given an {@link Iterable}<A>, produce an
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java
index 83c80e09a..0c91253d7 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Repeat.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions.builtin.fn1;
 
 import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.iteration.RepetitiousIterator;
+import com.jnape.palatable.lambda.internal.iteration.RepetitiousIterator;
 
 /**
  * Given a value, return an infinite Iterable that repeatedly iterates that value.
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java
index eaeecc014..54cbc5263 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Reverse.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions.builtin.fn1;
 
 import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.iteration.ReversingIterable;
+import com.jnape.palatable.lambda.internal.iteration.ReversingIterable;
 
 /**
  * Given an Iterable, return a reversed representation of that Iterable. Note that reversing
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java
index 2ef85c703..17b5ca94b 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProduct.java
@@ -3,7 +3,7 @@
 import com.jnape.palatable.lambda.adt.hlist.Tuple2;
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.CombinatorialIterator;
+import com.jnape.palatable.lambda.internal.iteration.CombinatorialIterator;
 
 /**
  * Lazily compute the cartesian product of an Iterable<A> and Iterable<B>,
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java
index 7ad8405a0..63dabbaf2 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Cons.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.ConsingIterator;
+import com.jnape.palatable.lambda.internal.iteration.ConsingIterator;
 
 /**
  * Prepend an element to an Iterable.
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java
index c975a0efb..7229e51e9 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Drop.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.DroppingIterable;
+import com.jnape.palatable.lambda.internal.iteration.DroppingIterable;
 
 /**
  * Lazily skip the first n elements from an Iterable by returning an Iterable
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java
index f91d8ba15..a39ff3942 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/DropWhile.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.PredicatedDroppingIterable;
+import com.jnape.palatable.lambda.internal.iteration.PredicatedDroppingIterable;
 
 /**
  * Lazily limit the Iterable by skipping the first contiguous group of elements that satisfy the predicate,
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java
index 2074ec59c..2b445ca11 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Filter.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.FilteringIterable;
+import com.jnape.palatable.lambda.internal.iteration.FilteringIterable;
 
 /**
  * Lazily apply a predicate to each element in an Iterable, returning an Iterable of just the
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java
index 5270cf60f..673d6c980 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOf.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.GroupingIterator;
+import com.jnape.palatable.lambda.internal.iteration.GroupingIterator;
 
 /**
  * Lazily group the Iterable by returning an Iterable of smaller Iterables of
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java
index f5f37332b..ace10d667 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Map.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.MappingIterable;
+import com.jnape.palatable.lambda.internal.iteration.MappingIterable;
 
 /**
  * Lazily apply a function to each element in an Iterable, producing an Iterable of the mapped
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java
index 7b2ed2a64..ad25f29f7 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/PrependAll.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.PrependingIterator;
+import com.jnape.palatable.lambda.internal.iteration.PrependingIterator;
 
 /**
  * Lazily prepend each value with of the Iterable with the supplied separator value. An empty
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java
index 67fe1a137..bfd8007bc 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Snoc.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.SnocIterable;
+import com.jnape.palatable.lambda.internal.iteration.SnocIterable;
 
 /**
  * Opposite of {@link Cons}: lazily append an element to the end of the given {@link Iterable}.
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java
index dbc55e349..15ddbcad2 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Take.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.TakingIterable;
+import com.jnape.palatable.lambda.internal.iteration.TakingIterable;
 
 /**
  * Lazily limit the Iterable to n elements by returning an Iterable that stops
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java
index d0d051dce..07524b7b4 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/TakeWhile.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.PredicatedTakingIterable;
+import com.jnape.palatable.lambda.internal.iteration.PredicatedTakingIterable;
 
 /**
  * Lazily limit the Iterable to the first group of contiguous elements that satisfy the predicate by
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java
index aa451768b..dbf8c8480 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Unfoldr.java
@@ -4,7 +4,7 @@
 import com.jnape.palatable.lambda.adt.hlist.Tuple2;
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
-import com.jnape.palatable.lambda.iteration.UnfoldingIterator;
+import com.jnape.palatable.lambda.internal.iteration.UnfoldingIterator;
 
 /**
  * Given an initial seed value and a function that takes the seed type and produces an {@link Maybe}<{@link
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java
index 49f77d96c..5db4f413a 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ScanLeft.java
@@ -3,7 +3,7 @@
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.functions.Fn3;
-import com.jnape.palatable.lambda.iteration.ScanningIterator;
+import com.jnape.palatable.lambda.internal.iteration.ScanningIterator;
 
 /**
  * Given an Iterable of As, a starting value B, and a
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java
index 96c072bd2..f9af0c1f2 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/ZipWith.java
@@ -3,9 +3,7 @@
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.functions.Fn3;
-import com.jnape.palatable.lambda.iteration.ZippingIterator;
-
-import java.util.function.BiFunction;
+import com.jnape.palatable.lambda.internal.iteration.ZippingIterator;
 
 /**
  * Zip together two Iterables by applying a zipping function to the successive elements of each
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java
index fa5a0844c..53d9b7189 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimit.java
@@ -5,8 +5,8 @@
 import com.jnape.palatable.lambda.functions.Fn2;
 import com.jnape.palatable.lambda.functions.Fn3;
 import com.jnape.palatable.lambda.functions.Fn4;
-import com.jnape.palatable.lambda.iteration.IterationInterruptedException;
-import com.jnape.palatable.lambda.iteration.RateLimitingIterable;
+import com.jnape.palatable.lambda.internal.iteration.IterationInterruptedException;
+import com.jnape.palatable.lambda.internal.iteration.RateLimitingIterable;
 
 import java.time.Duration;
 import java.time.Instant;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java
index a28e90614..198316f00 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/BiMonoidFactory.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.functions.specialized;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.monoid.Monoid;
 
 @FunctionalInterface
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java
index e4d993def..1bcbb4314 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/MonoidFactory.java
@@ -1,6 +1,6 @@
 package com.jnape.palatable.lambda.functions.specialized;
 
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.monoid.Monoid;
 
 public interface MonoidFactory extends SemigroupFactory {
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java
index 0f63478f6..71d91b5c8 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java
@@ -1,6 +1,6 @@
 package com.jnape.palatable.lambda.functions.specialized;
 
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.functor.Functor;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java
index 305fd900a..6295d4089 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java
@@ -1,6 +1,6 @@
 package com.jnape.palatable.lambda.functions.specialized;
 
-import com.jnape.palatable.lambda.functions.specialized.checked.Runtime;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.io.IO;
 
 /**
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java b/src/main/java/com/jnape/palatable/lambda/internal/Runtime.java
similarity index 76%
rename from src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java
rename to src/main/java/com/jnape/palatable/lambda/internal/Runtime.java
index 5ba88fd93..a280744fe 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/Runtime.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/Runtime.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.functions.specialized.checked;
+package com.jnape.palatable.lambda.internal;
 
 public final class Runtime {
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIterator.java
similarity index 96%
rename from src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIterator.java
index 219582f4a..11922226a 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/CombinatorialIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.adt.hlist.Tuple2;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java
similarity index 94%
rename from src/main/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java
index f7ae08023..594be70b2 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConsingIterator.java
similarity index 95%
rename from src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ConsingIterator.java
index 5198f66f7..b560974bb 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/ConsingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConsingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn0;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterable.java
similarity index 88%
rename from src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterable.java
index 6d08dbcf2..3218892b2 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterator.java
similarity index 94%
rename from src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterator.java
index 2705ffa06..827652a44 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/CyclicIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.ArrayList;
 import java.util.Iterator;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/DistinctIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterable.java
similarity index 91%
rename from src/main/java/com/jnape/palatable/lambda/iteration/DistinctIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterable.java
index 447b76168..19758a6df 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/DistinctIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.HashMap;
 import java.util.Iterator;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterable.java
similarity index 91%
rename from src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterable.java
index b545a296f..1d9534b17 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterator.java
similarity index 93%
rename from src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterator.java
index 5f69eb643..5b758695b 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/DroppingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterable.java
similarity index 95%
rename from src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterable.java
index 7503e152a..7accde2f8 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterator.java
similarity index 95%
rename from src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterator.java
index d283a1129..4a9346d40 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/FilteringIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/FlatteningIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIterator.java
similarity index 92%
rename from src/main/java/com/jnape/palatable/lambda/iteration/FlatteningIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIterator.java
index 40458cd48..f02759374 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/FlatteningIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java
similarity index 92%
rename from src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java
index fdaf95ebe..08d2f8c3f 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/GroupingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.ArrayList;
 import java.util.Iterator;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIterator.java
similarity index 81%
rename from src/main/java/com/jnape/palatable/lambda/iteration/ImmutableIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIterator.java
index 7252d2313..cc41f275d 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableQueue.java
similarity index 98%
rename from src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableQueue.java
index c7b109d3b..1b683c870 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableQueue.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableQueue.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.adt.Maybe;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableStack.java
similarity index 97%
rename from src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableStack.java
index e2ca4a8a2..a337ec21b 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/ImmutableStack.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableStack.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.adt.Maybe;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/InfiniteIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIterator.java
similarity index 73%
rename from src/main/java/com/jnape/palatable/lambda/iteration/InfiniteIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIterator.java
index 88b7c640d..f136da18d 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/InfiniteIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 public abstract class InfiniteIterator extends ImmutableIterator {
     @Override
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/InitIterator.java
similarity index 92%
rename from src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/InitIterator.java
index 0b1daa4e9..31eed515f 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/InitIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/InitIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/IterationInterruptedException.java
similarity index 88%
rename from src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/IterationInterruptedException.java
index ed3308961..c52797198 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/IterationInterruptedException.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/IterationInterruptedException.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.builtin.fn4.RateLimit;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterable.java
similarity index 95%
rename from src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterable.java
index 4bffb3b3d..3d2f1ba65 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterator.java
similarity index 91%
rename from src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterator.java
index ed13cf281..6fb64fd90 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/MappingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/MappingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java
similarity index 95%
rename from src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java
index 591e561f5..d87cf0e09 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java
similarity index 95%
rename from src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java
index 8bbba7783..7add62a45 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterable.java
similarity index 95%
rename from src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterable.java
index 8a612fa11..de9c7682e 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterator.java
similarity index 95%
rename from src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterator.java
index 6d228ae85..9760450b0 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/PrependingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PrependingIterator.java
similarity index 93%
rename from src/main/java/com/jnape/palatable/lambda/iteration/PrependingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/PrependingIterator.java
index 53755c0f2..8914c2aca 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/PrependingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PrependingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterable.java
similarity index 92%
rename from src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterable.java
index 63bb5611f..3a7c856d4 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.adt.hlist.Tuple3;
 import com.jnape.palatable.lambda.functions.Fn0;
@@ -8,7 +8,6 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
-import java.util.function.Supplier;
 
 public final class RateLimitingIterable implements Iterable {
     private final Iterable                               as;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterator.java
similarity index 98%
rename from src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterator.java
index 057106dd9..1046f406c 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/RateLimitingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RateLimitingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.adt.Try;
 import com.jnape.palatable.lambda.adt.hlist.Tuple3;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIterator.java
similarity index 81%
rename from src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIterator.java
index 51a6715a5..55652d4c4 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/RepetitiousIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 public final class RepetitiousIterator extends InfiniteIterator {
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterable.java
similarity index 92%
rename from src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterable.java
index df4c25e45..29aff81db 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterator.java
similarity index 94%
rename from src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterator.java
index 428898058..70e1baa60 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/ReversingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.ArrayList;
 import java.util.Iterator;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java
similarity index 96%
rename from src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java
index d4de2c5d7..5bdde4312 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/RewindableIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ScanningIterator.java
similarity index 94%
rename from src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ScanningIterator.java
index 187982cca..43fc4ece5 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/ScanningIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ScanningIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn2;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/SnocIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterable.java
similarity index 93%
rename from src/main/java/com/jnape/palatable/lambda/iteration/SnocIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterable.java
index a16947b4a..9a0118200 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/SnocIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Collections;
 import java.util.Iterator;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/SnocIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterator.java
similarity index 91%
rename from src/main/java/com/jnape/palatable/lambda/iteration/SnocIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterator.java
index 7c084c7ab..e3c336a91 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/SnocIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/SnocIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterable.java
similarity index 91%
rename from src/main/java/com/jnape/palatable/lambda/iteration/TakingIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterable.java
index ce67f8e89..f228b596a 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterator.java
similarity index 92%
rename from src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterator.java
index 3b558d68e..900f7ddb7 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/TakingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TakingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIterator.java
similarity index 95%
rename from src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIterator.java
index 146b19126..7ed719046 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/UnfoldingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.adt.Maybe;
 import com.jnape.palatable.lambda.adt.hlist.Tuple2;
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterable.java
similarity index 92%
rename from src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterable.java
index 641ab8255..fc4c6ed60 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/UnioningIterable.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterable.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import java.util.Iterator;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ZippingIterator.java
similarity index 93%
rename from src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java
rename to src/main/java/com/jnape/palatable/lambda/internal/iteration/ZippingIterator.java
index 20175de5c..107a6ec08 100644
--- a/src/main/java/com/jnape/palatable/lambda/iteration/ZippingIterator.java
+++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ZippingIterator.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn2;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java
index 002834bd1..83c7c31c8 100644
--- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java
+++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Concat.java
@@ -1,7 +1,7 @@
 package com.jnape.palatable.lambda.monoid.builtin;
 
 import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.iteration.ConcatenatingIterable;
+import com.jnape.palatable.lambda.internal.iteration.ConcatenatingIterable;
 import com.jnape.palatable.lambda.monoid.Monoid;
 
 import java.util.Collections;
diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java
index 8da150dc5..283bd2980 100644
--- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java
+++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Union.java
@@ -2,7 +2,7 @@
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct;
-import com.jnape.palatable.lambda.iteration.UnioningIterable;
+import com.jnape.palatable.lambda.internal.iteration.UnioningIterable;
 import com.jnape.palatable.lambda.monoid.Monoid;
 
 import java.util.Collections;
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java
index a03305b74..b91b92b08 100644
--- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/RateLimitTest.java
@@ -1,8 +1,7 @@
 package com.jnape.palatable.lambda.functions.builtin.fn4;
 
 import com.jnape.palatable.lambda.functions.Fn1;
-import com.jnape.palatable.lambda.functions.specialized.SideEffect;
-import com.jnape.palatable.lambda.iteration.IterationInterruptedException;
+import com.jnape.palatable.lambda.internal.iteration.IterationInterruptedException;
 import com.jnape.palatable.traitor.annotations.TestTraits;
 import com.jnape.palatable.traitor.runners.Traits;
 import org.junit.Before;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/CombinatorialIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java
similarity index 97%
rename from src/test/java/com/jnape/palatable/lambda/iteration/CombinatorialIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java
index 7678bd2c4..639136dd7 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/CombinatorialIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterableTest.java
similarity index 94%
rename from src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterableTest.java
index c82efdc70..92ffd28b9 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/ConcatenatingIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ConsingIteratorTest.java
similarity index 97%
rename from src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ConsingIteratorTest.java
index 301108b0f..85f6c6ba0 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/ConsingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ConsingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/CyclicIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterableTest.java
similarity index 88%
rename from src/test/java/com/jnape/palatable/lambda/iteration/CyclicIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterableTest.java
index 66938afa1..a4ce12dce 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/CyclicIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/CyclicIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIteratorTest.java
similarity index 92%
rename from src/test/java/com/jnape/palatable/lambda/iteration/CyclicIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIteratorTest.java
index ba7e84485..5af519d32 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/CyclicIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CyclicIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Test;
 
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/DistinctIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterableTest.java
similarity index 88%
rename from src/test/java/com/jnape/palatable/lambda/iteration/DistinctIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterableTest.java
index 69a2bd252..ae6d53ce5 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/DistinctIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DistinctIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterableTest.java
similarity index 88%
rename from src/test/java/com/jnape/palatable/lambda/iteration/DroppingIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterableTest.java
index 52ab7899f..cccdd2878 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java
similarity index 95%
rename from src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java
index 9bbdad7ad..b13dc33d1 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/DroppingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/FilteringIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterableTest.java
similarity index 91%
rename from src/test/java/com/jnape/palatable/lambda/iteration/FilteringIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterableTest.java
index 7d1c645d6..b2f40b516 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/FilteringIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/FilteringIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIteratorTest.java
similarity index 95%
rename from src/test/java/com/jnape/palatable/lambda/iteration/FilteringIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIteratorTest.java
index 5f2c3cb7e..68f3ab567 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/FilteringIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FilteringIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Test;
 
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/FlatteningIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIteratorTest.java
similarity index 96%
rename from src/test/java/com/jnape/palatable/lambda/iteration/FlatteningIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIteratorTest.java
index 7288e8fbc..ce286ecd2 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/FlatteningIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/FlatteningIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Test;
 
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/GroupingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java
similarity index 96%
rename from src/test/java/com/jnape/palatable/lambda/iteration/GroupingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java
index 0caab11a5..0288574d2 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/GroupingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIteratorTest.java
similarity index 92%
rename from src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIteratorTest.java
index da73c4aef..15369f60a 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/ImmutableIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ImmutableIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIteratorTest.java
similarity index 93%
rename from src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIteratorTest.java
index 7ce772cf6..a2df8b32c 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/InfiniteIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/InfiniteIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/InitIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/InitIteratorTest.java
similarity index 94%
rename from src/test/java/com/jnape/palatable/lambda/iteration/InitIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/InitIteratorTest.java
index 04c512cb3..99f12dee2 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/InitIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/InitIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Test;
 
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/MappingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIterableTest.java
similarity index 91%
rename from src/test/java/com/jnape/palatable/lambda/iteration/MappingIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIterableTest.java
index fdddf37e0..b86b95650 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/MappingIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/MappingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java
similarity index 91%
rename from src/test/java/com/jnape/palatable/lambda/iteration/MappingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java
index c4522f8c1..396982cdc 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/MappingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterableTest.java
similarity index 91%
rename from src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterableTest.java
index 2202c2b98..55d6a3ef1 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java
similarity index 97%
rename from src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java
index 68f933a9a..bb3afa82f 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedDroppingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import org.junit.Before;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterableTest.java
similarity index 91%
rename from src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterableTest.java
index bb8738cc5..e819c90f2 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java
similarity index 98%
rename from src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java
index 833ad43c8..70ba8953f 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/PredicatedTakingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.specialized.Predicate;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/PrependingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PrependingIteratorTest.java
similarity index 96%
rename from src/test/java/com/jnape/palatable/lambda/iteration/PrependingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/PrependingIteratorTest.java
index 84bdebc1a..4e922aa43 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/PrependingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PrependingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/RepetitiousIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIteratorTest.java
similarity index 93%
rename from src/test/java/com/jnape/palatable/lambda/iteration/RepetitiousIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIteratorTest.java
index bcf9d2628..f99823f25 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/RepetitiousIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RepetitiousIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterableTest.java
similarity index 90%
rename from src/test/java/com/jnape/palatable/lambda/iteration/ReversingIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterableTest.java
index e70b7cbd9..44ea4f446 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java
similarity index 97%
rename from src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java
index 391bcfb26..1fd9afce1 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/ReversingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java
similarity index 97%
rename from src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java
index a8bee457c..532397934 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/RewindableIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ScanningIteratorTest.java
similarity index 96%
rename from src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ScanningIteratorTest.java
index 9405ee45a..43d24fad0 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/ScanningIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ScanningIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn2;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/SnocIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIterableTest.java
similarity index 89%
rename from src/test/java/com/jnape/palatable/lambda/iteration/SnocIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIterableTest.java
index 258e872a3..6451e8b4f 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/SnocIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/SnocIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIteratorTest.java
similarity index 95%
rename from src/test/java/com/jnape/palatable/lambda/iteration/SnocIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIteratorTest.java
index 6fca49817..96080f32b 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/SnocIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/SnocIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/TakingIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIterableTest.java
similarity index 90%
rename from src/test/java/com/jnape/palatable/lambda/iteration/TakingIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIterableTest.java
index b1bd84454..e72b6f060 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/TakingIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/TakingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java
similarity index 92%
rename from src/test/java/com/jnape/palatable/lambda/iteration/TakingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java
index 9f17bcf4d..e6a03a6f2 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/TakingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java
@@ -1,7 +1,8 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import org.junit.Test;
 
+import java.util.Collections;
 import java.util.List;
 
 import static java.util.Arrays.asList;
@@ -40,7 +41,7 @@ public void doesNotHaveNextIfTakenAllOfIterable() {
 
     @Test
     public void doesNotHaveNextForEmptyIterable() {
-        TakingIterator takingIterator = new TakingIterator<>(3, emptyList().iterator());
+        TakingIterator takingIterator = new TakingIterator<>(3, Collections.emptyIterator());
         assertThat(takingIterator.hasNext(), is(false));
     }
 }
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/UnfoldingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIteratorTest.java
similarity index 96%
rename from src/test/java/com/jnape/palatable/lambda/iteration/UnfoldingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIteratorTest.java
index 68fa1ec9c..4b1199565 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/UnfoldingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/UnfoldingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.adt.Maybe;
 import com.jnape.palatable.lambda.adt.hlist.Tuple2;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterableTest.java
similarity index 94%
rename from src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterableTest.java
index dddec5ad9..b28bc2b61 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/UnioningIterableTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/UnioningIterableTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn1;
 import com.jnape.palatable.traitor.annotations.TestTraits;
diff --git a/src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java
similarity index 96%
rename from src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java
rename to src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java
index 58b351f6f..96e655db0 100644
--- a/src/test/java/com/jnape/palatable/lambda/iteration/ZippingIteratorTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java
@@ -1,4 +1,4 @@
-package com.jnape.palatable.lambda.iteration;
+package com.jnape.palatable.lambda.internal.iteration;
 
 import com.jnape.palatable.lambda.functions.Fn2;
 import org.junit.Before;

From d27225cc559c77964774736a15e45a7f21422a56 Mon Sep 17 00:00:00 2001
From: jnape 
Date: Thu, 9 May 2019 20:18:19 -0500
Subject: [PATCH 148/348] Improving inference for Pure

---
 .../jnape/palatable/lambda/functions/specialized/Pure.java | 7 ++++---
 src/main/java/com/jnape/palatable/lambda/optics/Prism.java | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java
index 71d91b5c8..a49cf98b6 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java
@@ -1,8 +1,8 @@
 package com.jnape.palatable.lambda.functions.specialized;
 
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.functor.Functor;
+import com.jnape.palatable.lambda.internal.Runtime;
 
 /**
  * Generalized, portable {@link Applicative#pure(Object)}, with a loosened {@link Functor} constraint.
@@ -14,9 +14,10 @@ public interface Pure> {
 
      Functor checkedApply(A a) throws Throwable;
 
-    default  Functor apply(A a) {
+    default > FA apply(A a) {
         try {
-            return checkedApply(a);
+            @SuppressWarnings("unchecked") FA fa = (FA) checkedApply(a);
+            return fa;
         } catch (Throwable t) {
             throw Runtime.throwChecked(t);
         }
diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java
index b52f67fd0..d83f01774 100644
--- a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java
+++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java
@@ -95,7 +95,7 @@ static  Prism prism(Fn1, ?>,
                         Cocartesian, ?>>optic(pafb -> pafb.cocartesian()
                         .diMap(s -> sta.apply(s).match(Choice2::a, Choice2::b),
-                               tOrFb -> tOrFb.match(pure::apply, fb -> fb.fmap(bt))));
+                               tOrFb -> tOrFb.>match(pure::apply, fb -> fb.fmap(bt))));
             }
         };
     }

From d32692ce987588e3385513c9ecf36e38c81f0db0 Mon Sep 17 00:00:00 2001
From: jnape 
Date: Thu, 9 May 2019 20:20:52 -0500
Subject: [PATCH 149/348] Removing Noop and offering a constant SideEffect NOOP

---
 CHANGELOG.md                                  |  1 +
 .../lambda/functions/specialized/Noop.java    | 36 -------------------
 .../functions/specialized/SideEffect.java     |  5 +++
 3 files changed, 6 insertions(+), 36 deletions(-)
 delete mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 76b7ca7cb..c74f691eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -43,6 +43,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
 - `Market`, `Tagged`, profunctors supporting optics 
 - `Re` for viewing an `Optic` in one direction reliably
 - `Pre` for viewing at most one value from an `Optic` in one direction
+- `SideEffect`, for representing side-effects runnable by `IO`
 
 ## [3.3.0] - 2019-02-18
 ### Added
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java
deleted file mode 100644
index 73a867626..000000000
--- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Noop.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.jnape.palatable.lambda.functions.specialized;
-
-import com.jnape.palatable.lambda.adt.Unit;
-import com.jnape.palatable.lambda.functions.Effect;
-import com.jnape.palatable.lambda.io.IO;
-
-import static com.jnape.palatable.lambda.adt.Unit.UNIT;
-import static com.jnape.palatable.lambda.io.IO.io;
-
-/**
- * As the name might suggest, this is an {@link Effect} that, *ahem*, has no effect.
- *
- * @param  the argument type
- */
-public final class Noop implements Effect {
-    private static final Noop INSTANCE = new Noop<>();
-
-    private Noop() {
-    }
-
-    @Override
-    public IO checkedApply(A a) throws Throwable {
-        return io(UNIT);
-    }
-
-    /**
-     * Static factory method that returns the singleton {@link Noop} instance.
-     *
-     * @param  the argument type
-     * @return the singleton {@link Noop} instance
-     */
-    @SuppressWarnings("unchecked")
-    public static  Noop noop() {
-        return (Noop) INSTANCE;
-    }
-}
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java
index 6295d4089..f0872ed9e 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java
@@ -14,6 +14,11 @@
  */
 public interface SideEffect {
 
+    /**
+     * A no-op {@link SideEffect}
+     */
+    @SuppressWarnings("unused") SideEffect NOOP = () -> {};
+
     @SuppressWarnings("NonAsciiCharacters")
     void Ω() throws Throwable;
 

From e8a0352fc0501e2e9a48c8b1b9ea003da109953c Mon Sep 17 00:00:00 2001
From: jnape 
Date: Sat, 11 May 2019 17:04:17 -0500
Subject: [PATCH 150/348] IO#safe, IO#ensuring, and IO#throwing

---
 CHANGELOG.md                                  |  3 +
 .../com/jnape/palatable/lambda/io/IO.java     | 40 +++++++++++
 .../com/jnape/palatable/lambda/io/IOTest.java | 67 +++++++++++++++++++
 3 files changed, 110 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c74f691eb..106373584 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -44,6 +44,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
 - `Re` for viewing an `Optic` in one direction reliably
 - `Pre` for viewing at most one value from an `Optic` in one direction
 - `SideEffect`, for representing side-effects runnable by `IO`
+- `IO#safe`, mapping an `IO` to an `IO>` that will never throw
+- `IO#ensuring`, like `finally` semantics for `IO`s
+- `IO#throwing`, for producing an `IO` that will throw a given `Throwable` when executed
 
 ## [3.3.0] - 2019-02-18
 ### Added
diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java
index 2848da1fc..6036d1335 100644
--- a/src/main/java/com/jnape/palatable/lambda/io/IO.java
+++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java
@@ -1,5 +1,6 @@
 package com.jnape.palatable.lambda.io;
 
+import com.jnape.palatable.lambda.adt.Either;
 import com.jnape.palatable.lambda.adt.Try;
 import com.jnape.palatable.lambda.adt.Unit;
 import com.jnape.palatable.lambda.adt.choice.Choice2;
@@ -19,11 +20,13 @@
 import static com.jnape.palatable.lambda.adt.choice.Choice2.a;
 import static com.jnape.palatable.lambda.adt.hlist.HList.tuple;
 import static com.jnape.palatable.lambda.functions.Fn0.fn0;
+import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
 import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft;
 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 com.jnape.palatable.lambda.monad.Monad.join;
 import static java.util.concurrent.CompletableFuture.completedFuture;
 import static java.util.concurrent.CompletableFuture.supplyAsync;
 import static java.util.concurrent.ForkJoinPool.commonPool;
@@ -93,6 +96,32 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) {
         };
     }
 
+    /**
+     * Return an {@link IO} that will run ensureIO strictly after running this {@link IO} regardless of
+     * whether this {@link IO} terminates normally, analogous to a finally block.
+     *
+     * @param ensureIO the {@link IO} to ensure runs strictly after this {@link IO}
+     * @return the combined {@link IO}
+     */
+    public final IO ensuring(IO ensureIO) {
+        return join(fmap(a -> ensureIO.fmap(constantly(a)))
+                            .exceptionally(t -> join(ensureIO.>fmap(constantly(io(() -> {throw t;})))
+                                                             .exceptionally(t2 -> io(() -> {
+                                                                 t.addSuppressed(t2);
+                                                                 throw t;
+                                                             })))));
+    }
+
+    /**
+     * Return a safe {@link IO} that will never throw by lifting the result of this {@link IO} into {@link Either},
+     * catching any {@link Throwable} and wrapping it in a {@link Either#left(Object) left}.
+     *
+     * @return the safe {@link IO}
+     */
+    public final IO> safe() {
+        return fmap(Either::right).exceptionally(Either::left);
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -157,6 +186,17 @@ public final  IO flatMap(Fn1>> f) {
         return new Compose<>(source, Choice2.b(flatMap));
     }
 
+    /**
+     * Produce an {@link IO} that throws the given {@link Throwable} when executed.
+     *
+     * @param t   the {@link Throwable}
+     * @param  any result type
+     * @return the {@link IO}
+     */
+    public static  IO throwing(Throwable t) {
+        return io(() -> {throw t;});
+    }
+
     /**
      * Static factory method for creating an {@link IO} that just returns a when performed.
      *
diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java
index 7d1659ad2..2c86683e3 100644
--- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java
+++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java
@@ -13,8 +13,13 @@
 
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
 
+import static com.jnape.palatable.lambda.adt.Either.left;
+import static com.jnape.palatable.lambda.adt.Either.right;
 import static com.jnape.palatable.lambda.adt.Unit.UNIT;
 import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler;
 import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times;
@@ -23,7 +28,9 @@
 import static java.util.concurrent.CompletableFuture.completedFuture;
 import static java.util.concurrent.Executors.newFixedThreadPool;
 import static java.util.concurrent.ForkJoinPool.commonPool;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static testsupport.Constants.STACK_EXPLODING_NUMBER;
 
 @RunWith(Traits.class)
@@ -174,6 +181,66 @@ public IO checkedApply(IO a) {
                              return a.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(io(x + 1)) : io(x));
                          }
                      }.apply(io(0)).unsafePerformAsyncIO().join());
+    }
+
+    @Test
+    public void safe() {
+        assertEquals(right(1), io(() -> 1).safe().unsafePerformIO());
+        IllegalStateException thrown = new IllegalStateException("kaboom");
+        assertEquals(left(thrown), io(() -> {throw thrown;}).safe().unsafePerformIO());
+    }
+
+    @Test
+    public void ensuring() {
+        AtomicInteger counter    = new AtomicInteger(0);
+        IO   incCounter = io(counter::incrementAndGet);
+        assertEquals("foo", io(() -> "foo").ensuring(incCounter).unsafePerformIO());
+        assertEquals(1, counter.get());
+
+        IllegalStateException thrown = new IllegalStateException("kaboom");
+        try {
+            io(() -> {throw thrown;}).ensuring(incCounter).unsafePerformIO();
+            fail("Expected exception to have been thrown, but wasn't.");
+        } catch (IllegalStateException actual) {
+            assertEquals(thrown, actual);
+            assertEquals(2, counter.get());
+        }
+    }
 
+    @Test
+    public void ensuringRunsStrictlyAfterIO() {
+        Executor      twoThreads = Executors.newFixedThreadPool(2);
+        AtomicInteger counter    = new AtomicInteger(0);
+        io(() -> {
+            Thread.sleep(100);
+            counter.incrementAndGet();
+        }).ensuring(io(() -> {
+            if (counter.get() == 0)
+                fail("Expected to run after initial IO, but ran first");
+        })).unsafePerformAsyncIO(twoThreads).join();
+    }
+
+    @Test
+    public void ensuringAttachesThrownExceptionToThrownBodyException() {
+        IllegalStateException thrownByBody     = new IllegalStateException("kaboom");
+        IllegalStateException thrownByEnsuring = new IllegalStateException("KABOOM");
+
+        try {
+            io(() -> {throw thrownByBody;}).ensuring(io(() -> {throw thrownByEnsuring;})).unsafePerformIO();
+            fail("Expected exception to have been thrown, but wasn't.");
+        } catch (IllegalStateException actual) {
+            assertEquals(thrownByBody, actual);
+            assertArrayEquals(new Throwable[]{thrownByEnsuring}, actual.getSuppressed());
+        }
+    }
+
+    @Test
+    public void throwing() {
+        IllegalStateException expected = new IllegalStateException("thrown");
+        try {
+            IO.throwing(expected).unsafePerformIO();
+        } catch (IllegalStateException actual) {
+            assertEquals(expected, actual);
+        }
     }
 }
\ No newline at end of file

From a88cd97ca1a4cbc2b27e75c4a9528df7310bd278 Mon Sep 17 00:00:00 2001
From: jnape 
Date: Sat, 11 May 2019 17:27:05 -0500
Subject: [PATCH 151/348] Bracket for producing a value from an IO that can be
 cleaned up

---
 CHANGELOG.md                                  |  1 +
 .../lambda/functions/builtin/fn3/Bracket.java | 52 +++++++++++++
 .../functions/builtin/fn3/BracketTest.java    | 77 +++++++++++++++++++
 3 files changed, 130 insertions(+)
 create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Bracket.java
 create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 106373584..cc0afb897 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -47,6 +47,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
 - `IO#safe`, mapping an `IO` to an `IO>` that will never throw
 - `IO#ensuring`, like `finally` semantics for `IO`s
 - `IO#throwing`, for producing an `IO` that will throw a given `Throwable` when executed
+- `Bracket`, for bracketing an `IO` operation with a mapping operation and a cleanup operation 
 
 ## [3.3.0] - 2019-02-18
 ### Added
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Bracket.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Bracket.java
new file mode 100644
index 000000000..59e6f512d
--- /dev/null
+++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Bracket.java
@@ -0,0 +1,52 @@
+package com.jnape.palatable.lambda.functions.builtin.fn3;
+
+import com.jnape.palatable.lambda.functions.Fn1;
+import com.jnape.palatable.lambda.functions.Fn2;
+import com.jnape.palatable.lambda.functions.Fn3;
+import com.jnape.palatable.lambda.io.IO;
+import com.jnape.palatable.lambda.monad.Monad;
+
+/**
+ * Given an {@link IO} that yields some type A, a cleanup operation to run if a value of that type could be
+ * provisioned, and a kleisli arrow from that type to a new {@link IO} of type B, produce an
+ * {@link IO}<B> that, when run, will provision the A,
+ * {@link Monad#flatMap(Fn1) flatMap} it to B, and clean up the original value if it was produced in the
+ * first place.
+ *
+ * @param  the initial value to map and clean up
+ * @param  the resulting type
+ */
+public final class Bracket implements
+        Fn3, Fn1>, Fn1>, IO> {
+
+    private static final Bracket INSTANCE = new Bracket<>();
+
+    private Bracket() {
+    }
+
+    @Override
+    public IO checkedApply(IO io, Fn1> cleanupIO,
+                              Fn1> bodyIO) throws Throwable {
+        return io.flatMap(a -> bodyIO.apply(a).ensuring(cleanupIO.apply(a)));
+    }
+
+    @SuppressWarnings("unchecked")
+    public static  Bracket bracket() {
+        return (Bracket) INSTANCE;
+    }
+
+    public static  Fn2>, Fn1>, IO> bracket(
+            IO io) {
+        return Bracket.bracket().apply(io);
+    }
+
+    public static  Fn1>, IO> bracket(
+            IO io, Fn1> cleanupIO) {
+        return Bracket.bracket(io).apply(cleanupIO);
+    }
+
+    public static  IO bracket(IO io, Fn1> cleanupIO,
+                                       Fn1> bodyIO) {
+        return Bracket.bracket(io, cleanupIO).apply(bodyIO);
+    }
+}
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java
new file mode 100644
index 000000000..389ca5508
--- /dev/null
+++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java
@@ -0,0 +1,77 @@
+package com.jnape.palatable.lambda.functions.builtin.fn3;
+
+import com.jnape.palatable.lambda.io.IO;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static com.jnape.palatable.lambda.functions.builtin.fn3.Bracket.bracket;
+import static com.jnape.palatable.lambda.io.IO.io;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class BracketTest {
+
+    private AtomicInteger count;
+
+    @Before
+    public void setUp() {
+        count = new AtomicInteger(0);
+    }
+
+    @Test
+    public void cleanupHappyPath() {
+        IO hashIO = bracket(io(() -> count), c -> io(c::incrementAndGet), c -> io(c::hashCode));
+
+        assertEquals(0, count.get());
+        assertEquals((Integer) count.hashCode(), hashIO.unsafePerformIO());
+        assertEquals(1, count.get());
+    }
+
+    @Test
+    public void cleanupSadPath() {
+        IllegalStateException thrown = new IllegalStateException("kaboom");
+        IO           hashIO = bracket(io(count), c -> io(c::incrementAndGet), c -> io(() -> {throw thrown;}));
+
+        try {
+            hashIO.unsafePerformIO();
+            fail("Expected exception to be raised");
+        } catch (IllegalStateException actual) {
+            assertEquals(thrown, actual);
+            assertEquals(1, count.get());
+        }
+    }
+
+    @Test
+    public void cleanupOnlyRunsIfInitialIORuns() {
+        IllegalStateException thrown = new IllegalStateException("kaboom");
+        IO hashIO = bracket(io(() -> {throw thrown;}),
+                                     __ -> io(count::incrementAndGet),
+                                     __ -> io(count::incrementAndGet));
+        try {
+            hashIO.unsafePerformIO();
+            fail("Expected exception to be raised");
+        } catch (IllegalStateException actual) {
+            assertEquals(thrown, actual);
+            assertEquals(0, count.get());
+        }
+    }
+
+    @Test
+    public void errorsInCleanupAreAddedToBodyErrors() {
+        IllegalStateException bodyError    = new IllegalStateException("kaboom");
+        IllegalStateException cleanupError = new IllegalStateException("KABOOM");
+        IO hashIO = bracket(io(count),
+                                     c -> io(() -> {throw cleanupError;}),
+                                     c -> io(() -> {throw bodyError;}));
+        try {
+            hashIO.unsafePerformIO();
+            fail("Expected exception to be raised");
+        } catch (IllegalStateException actual) {
+            assertEquals(bodyError, actual);
+            assertArrayEquals(new Throwable[]{cleanupError}, actual.getSuppressed());
+        }
+    }
+}
\ No newline at end of file

From 3af50faef1bf6aad29fb5b039e3d384ea98d8d4e Mon Sep 17 00:00:00 2001
From: jnape 
Date: Sat, 11 May 2019 20:13:20 -0500
Subject: [PATCH 152/348] Updating travis yml for jdk 11

---
 .travis.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.travis.yml b/.travis.yml
index 9bcf99945..8ea4e5783 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,4 @@
 language: java
 jdk:
   - oraclejdk8
+  - oraclejdk11

From b0949c9a4a0cdc8ce2dd3543123226927a297adb Mon Sep 17 00:00:00 2001
From: jnape 
Date: Sat, 11 May 2019 20:13:52 -0500
Subject: [PATCH 153/348] Adding Pure static factory method to aid inference
 pre-11

---
 .../lambda/functions/specialized/Pure.java       | 11 +++++++++++
 .../lambda/functions/specialized/PureTest.java   | 16 ++++++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/specialized/PureTest.java

diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java
index a49cf98b6..77d3bd91a 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java
@@ -22,4 +22,15 @@ public interface Pure> {
             throw Runtime.throwChecked(t);
         }
     }
+
+    /**
+     * Static method to aid inference.
+     *
+     * @param pure the {@link Pure}
+     * @param   the {@link Functor} witness
+     * @return the {@link Pure}
+     */
+    static > Pure pure(Pure pure) {
+        return pure;
+    }
 }
diff --git a/src/test/java/com/jnape/palatable/lambda/functions/specialized/PureTest.java b/src/test/java/com/jnape/palatable/lambda/functions/specialized/PureTest.java
new file mode 100644
index 000000000..cda6be607
--- /dev/null
+++ b/src/test/java/com/jnape/palatable/lambda/functions/specialized/PureTest.java
@@ -0,0 +1,16 @@
+package com.jnape.palatable.lambda.functions.specialized;
+
+import com.jnape.palatable.lambda.adt.Maybe;
+import org.junit.Test;
+
+import static com.jnape.palatable.lambda.adt.Maybe.just;
+import static org.junit.Assert.assertEquals;
+
+public class PureTest {
+
+    @Test
+    @SuppressWarnings("RedundantTypeArguments")
+    public void inference() {
+        assertEquals(just(1), Pure.>pure(Maybe::just).>apply(1));
+    }
+}
\ No newline at end of file

From 576292ca0929eb018277ffb2294c894b54cb27e9 Mon Sep 17 00:00:00 2001
From: jnape 
Date: Sun, 12 May 2019 16:37:16 -0500
Subject: [PATCH 154/348] Removing extraneous imports

---
 src/main/java/com/jnape/palatable/lambda/adt/Try.java           | 2 +-
 .../com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java    | 2 --
 .../com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java    | 2 --
 src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java  | 2 --
 src/main/java/com/jnape/palatable/lambda/functions/Effect.java  | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn1.java     | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn2.java     | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn3.java     | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn4.java     | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn5.java     | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn6.java     | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn7.java     | 2 +-
 src/main/java/com/jnape/palatable/lambda/functions/Fn8.java     | 2 +-
 .../com/jnape/palatable/lambda/monad/transformer/MonadT.java    | 2 --
 .../palatable/lambda/monad/transformer/builtin/IdentityT.java   | 1 -
 .../java/com/jnape/palatable/lambda/optics/lenses/SetLens.java  | 1 -
 .../java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java   | 1 -
 .../java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java   | 2 --
 .../java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java   | 2 --
 .../java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java   | 2 --
 .../java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java   | 2 --
 .../java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java   | 2 --
 src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java | 1 -
 .../palatable/lambda/functions/builtin/fn2/GroupByTest.java     | 1 -
 .../palatable/lambda/internal/iteration/TakingIteratorTest.java | 1 -
 .../palatable/lambda/monad/transformer/builtin/MaybeTTest.java  | 1 -
 src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java  | 2 --
 .../testsupport/applicatives/InvocationRecordingBifunctor.java  | 1 -
 src/test/java/testsupport/assertion/LensAssert.java             | 1 -
 src/test/java/testsupport/functions/ExplainFold.java            | 2 --
 src/test/java/testsupport/traits/ApplicativeLaws.java           | 1 -
 src/test/java/testsupport/traits/FunctorLaws.java               | 2 --
 src/test/java/testsupport/traits/MonadLaws.java                 | 2 --
 src/test/java/testsupport/traits/TraversableLaws.java           | 2 --
 34 files changed, 10 insertions(+), 48 deletions(-)

diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java
index e89854b39..adaae9a85 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java
@@ -12,13 +12,13 @@
 
 import java.util.Objects;
 
-import static com.jnape.palatable.lambda.internal.Runtime.throwChecked;
 import static com.jnape.palatable.lambda.adt.Maybe.nothing;
 import static com.jnape.palatable.lambda.adt.Unit.UNIT;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast;
 import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy;
+import static com.jnape.palatable.lambda.internal.Runtime.throwChecked;
 
 /**
  * A {@link Monad} of the evaluation outcome of an expression that might throw. Try/catch/finally semantics map to
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java
index c8466dfa1..4deea96eb 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct4.java
@@ -5,8 +5,6 @@
 import com.jnape.palatable.lambda.adt.product.Product4;
 import com.jnape.palatable.lambda.functions.Fn1;
 
-import java.util.function.Function;
-
 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;
diff --git a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java
index 084b3860d..d8d8d2301 100644
--- a/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java
+++ b/src/main/java/com/jnape/palatable/lambda/adt/coproduct/CoProduct6.java
@@ -5,8 +5,6 @@
 import com.jnape.palatable.lambda.adt.product.Product6;
 import com.jnape.palatable.lambda.functions.Fn1;
 
-import java.util.function.Function;
-
 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;
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 74f21bc8f..01ed4cf6c 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
@@ -9,8 +9,6 @@
 import com.jnape.palatable.lambda.monad.Monad;
 import com.jnape.palatable.lambda.traversable.Traversable;
 
-import java.util.function.Function;
-
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
 
 /**
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java
index 4fdfba136..21b9ed723 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java
@@ -2,8 +2,8 @@
 
 import com.jnape.palatable.lambda.adt.Unit;
 import com.jnape.palatable.lambda.functions.specialized.SideEffect;
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.io.IO;
 
 import java.util.function.Consumer;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java
index 9df14981a..fcf44bd69 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java
@@ -3,11 +3,11 @@
 import com.jnape.palatable.lambda.adt.Either;
 import com.jnape.palatable.lambda.adt.choice.Choice2;
 import com.jnape.palatable.lambda.adt.hlist.Tuple2;
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.functor.Cartesian;
 import com.jnape.palatable.lambda.functor.Cocartesian;
 import com.jnape.palatable.lambda.functor.builtin.Lazy;
+import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.monad.Monad;
 
 import java.util.function.Function;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java
index 977082ed2..769f0a4d1 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java
@@ -1,8 +1,8 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
+import com.jnape.palatable.lambda.internal.Runtime;
 
 import java.util.function.BiFunction;
 
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java
index a225f7e3a..881d848ff 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn3.java
@@ -1,8 +1,8 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
+import com.jnape.palatable.lambda.internal.Runtime;
 
 import static com.jnape.palatable.lambda.functions.Fn4.fn4;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java
index e43dcda17..f2e9f7d47 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn4.java
@@ -1,8 +1,8 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
+import com.jnape.palatable.lambda.internal.Runtime;
 
 import static com.jnape.palatable.lambda.functions.Fn5.fn5;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java
index 55364e8bb..c89b8dadd 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn5.java
@@ -1,8 +1,8 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
+import com.jnape.palatable.lambda.internal.Runtime;
 
 import static com.jnape.palatable.lambda.functions.Fn6.fn6;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java
index 5998bc9aa..4e7bbea89 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn6.java
@@ -1,8 +1,8 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
+import com.jnape.palatable.lambda.internal.Runtime;
 
 import static com.jnape.palatable.lambda.functions.Fn7.fn7;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java
index 87a3f8704..2d27e6be2 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java
@@ -1,8 +1,8 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
+import com.jnape.palatable.lambda.internal.Runtime;
 
 import static com.jnape.palatable.lambda.functions.Fn8.fn8;
 import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java
index 4ead63674..a38e74eb1 100644
--- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java
+++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java
@@ -1,8 +1,8 @@
 package com.jnape.palatable.lambda.functions;
 
 import com.jnape.palatable.lambda.adt.product.Product2;
-import com.jnape.palatable.lambda.internal.Runtime;
 import com.jnape.palatable.lambda.functor.Applicative;
+import com.jnape.palatable.lambda.internal.Runtime;
 
 /**
  * A function taking six arguments. Defined in terms of {@link Fn7}, so similarly auto-curried.
diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java
index e95bdd68d..17b6dfd4e 100644
--- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java
+++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java
@@ -6,8 +6,6 @@
 import com.jnape.palatable.lambda.monad.Monad;
 import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT;
 
-import java.util.function.Function;
-
 /**
  * An interface representing a {@link Monad} transformer.
  * 

diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java index 26ffffb51..a3e87e3fc 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java @@ -9,7 +9,6 @@ import com.jnape.palatable.lambda.monad.transformer.MonadT; import java.util.Objects; -import java.util.function.Function; /** * A {@link MonadT monad transformer} for {@link Identity}. diff --git a/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java index 3c2790d53..6b66649ed 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java @@ -8,7 +8,6 @@ import java.util.Set; import static com.jnape.palatable.lambda.optics.Lens.simpleLens; -import static java.util.Collections.singleton; /** * Lenses that operate on {@link Set}s. diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index e4a4ee0bb..75d4bcbe2 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -14,7 +14,6 @@ import java.util.HashMap; import java.util.Map; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.hlist.HList.singletonHList; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java index 4a086c5f4..d52b407bb 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java @@ -12,8 +12,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java index 59280ec53..4e0fa9659 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java @@ -12,8 +12,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index 970ee1c62..45e4edc67 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -13,8 +13,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index 796ed4752..1fb7ab578 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -13,8 +13,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index b8c07e3db..6203fe15e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -13,8 +13,6 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java index b5c9413b3..dbe1d5b7a 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java @@ -8,7 +8,6 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; public class Fn2Test { diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java index b04ea7999..5a9401099 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java @@ -10,7 +10,6 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.GroupBy.groupBy; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java index e6a03a6f2..d22dd8138 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java @@ -6,7 +6,6 @@ import java.util.List; import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java index 8060ce8b3..9a5368cdc 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java @@ -1,7 +1,6 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Either; -import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; diff --git a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java index 46d617e81..81b74b14e 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java @@ -5,8 +5,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import org.junit.Test; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; diff --git a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java index 8fca9d114..a39803ee1 100644 --- a/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java +++ b/src/test/java/testsupport/applicatives/InvocationRecordingBifunctor.java @@ -4,7 +4,6 @@ import com.jnape.palatable.lambda.functor.Bifunctor; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; public final class InvocationRecordingBifunctor implements Bifunctor> { private final AtomicReference> leftFn; diff --git a/src/test/java/testsupport/assertion/LensAssert.java b/src/test/java/testsupport/assertion/LensAssert.java index b966e97f2..aea73adb5 100644 --- a/src/test/java/testsupport/assertion/LensAssert.java +++ b/src/test/java/testsupport/assertion/LensAssert.java @@ -6,7 +6,6 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Map; import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.lambda.optics.Optic; diff --git a/src/test/java/testsupport/functions/ExplainFold.java b/src/test/java/testsupport/functions/ExplainFold.java index 488b05476..d59a2378b 100644 --- a/src/test/java/testsupport/functions/ExplainFold.java +++ b/src/test/java/testsupport/functions/ExplainFold.java @@ -2,8 +2,6 @@ import com.jnape.palatable.lambda.functions.Fn2; -import java.util.function.BiFunction; - import static java.lang.String.format; public class ExplainFold { diff --git a/src/test/java/testsupport/traits/ApplicativeLaws.java b/src/test/java/testsupport/traits/ApplicativeLaws.java index 5b8b0b713..e449fe603 100644 --- a/src/test/java/testsupport/traits/ApplicativeLaws.java +++ b/src/test/java/testsupport/traits/ApplicativeLaws.java @@ -7,7 +7,6 @@ import com.jnape.palatable.traitor.traits.Trait; import java.util.Random; -import java.util.function.Function; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; diff --git a/src/test/java/testsupport/traits/FunctorLaws.java b/src/test/java/testsupport/traits/FunctorLaws.java index c2bb1791c..13ad2b423 100644 --- a/src/test/java/testsupport/traits/FunctorLaws.java +++ b/src/test/java/testsupport/traits/FunctorLaws.java @@ -6,8 +6,6 @@ import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; diff --git a/src/test/java/testsupport/traits/MonadLaws.java b/src/test/java/testsupport/traits/MonadLaws.java index 5ea31ac98..6a2df2392 100644 --- a/src/test/java/testsupport/traits/MonadLaws.java +++ b/src/test/java/testsupport/traits/MonadLaws.java @@ -6,8 +6,6 @@ import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; diff --git a/src/test/java/testsupport/traits/TraversableLaws.java b/src/test/java/testsupport/traits/TraversableLaws.java index 3939c3c3d..f27eca241 100644 --- a/src/test/java/testsupport/traits/TraversableLaws.java +++ b/src/test/java/testsupport/traits/TraversableLaws.java @@ -10,8 +10,6 @@ import com.jnape.palatable.lambda.traversable.Traversable; import com.jnape.palatable.traitor.traits.Trait; -import java.util.function.Function; - import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; From c0752977a98a76a0bba2818e472af8fcb1da2265 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 13 May 2019 17:46:21 -0500 Subject: [PATCH 155/348] Adding Effect#noop back, it's just too convenient --- .../com/jnape/palatable/lambda/functions/Effect.java | 11 +++++++++++ .../lambda/functions/specialized/SideEffect.java | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 21b9ed723..6e23e2932 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -10,6 +10,7 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.specialized.SideEffect.NOOP; import static com.jnape.palatable.lambda.io.IO.io; /** @@ -90,6 +91,16 @@ static Effect effect(SideEffect sideEffect) { return effect(constantly(io(sideEffect))); } + /** + * Create an {@link Effect} that accepts an input and does nothing; + * + * @return the noop {@link Effect} + */ + @SuppressWarnings("unused") + static Effect noop() { + return effect(NOOP).contraMap(constantly(UNIT)); + } + /** * Create an {@link Effect} from an {@link Fn1} that yields an {@link IO}. * diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java index f0872ed9e..6ef2092a1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/SideEffect.java @@ -17,7 +17,7 @@ public interface SideEffect { /** * A no-op {@link SideEffect} */ - @SuppressWarnings("unused") SideEffect NOOP = () -> {}; + SideEffect NOOP = () -> {}; @SuppressWarnings("NonAsciiCharacters") void Ω() throws Throwable; From 17309bfac547f39c3d6c9e89e8d9bacd84c0f8df Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 14 May 2019 19:33:57 -0500 Subject: [PATCH 156/348] IO internally composes using the given Executor, rather than the FJP --- src/main/java/com/jnape/palatable/lambda/io/IO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 6036d1335..a42181bd2 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -316,7 +316,7 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { .match(zip -> zip.unsafePerformAsyncIO(executor) .thenCompose(f -> io.thenApply(f.toFunction())), flatMap -> io.thenComposeAsync(obj -> flatMap.apply(obj) - .unsafePerformAsyncIO(executor))), + .unsafePerformAsyncIO(executor), executor)), source.unsafePerformAsyncIO(executor), compositions)); return future; From 51590cd2fac0431bf825583409a53eaa82e7410f Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 14 May 2019 19:45:42 -0500 Subject: [PATCH 157/348] Try#failure loses extraneous parameter; Try#orThrow can transform first --- .../com/jnape/palatable/lambda/adt/Try.java | 30 ++++++++++++++----- .../jnape/palatable/lambda/adt/TryTest.java | 25 ++++++++++++---- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index adaae9a85..00b629a72 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -110,7 +110,24 @@ public final Throwable forfeit(Fn1 fn) { * @return possibly the success value * @throws T anything that the call site may want to explicitly catch or indicate could be thrown */ - public abstract A orThrow() throws T; + public final A orThrow() throws T { + try { + return orThrow(id()); + } catch (Throwable t) { + throw throwChecked(t); + } + } + + /** + * If this is a success value, return it. Otherwise, transform the captured failure with fn and throw + * the result. + * + * @param the type of the thrown {@link Throwable} + * @return possibly the success value + * @throws T the transformation output + */ + public abstract A orThrow(Fn1 fn) throws T; + /** * If this is a success, wrap the value in a {@link Maybe#just} and return it. Otherwise, return {@link @@ -228,12 +245,11 @@ public static Try success(A a) { /** * Static factory method for creating a failure value. * - * @param t the wrapped {@link Throwable} - * @param the failure parameter type + * @param t the {@link Throwable} * @param the success parameter type * @return a failure value of t */ - public static Try failure(T t) { + public static Try failure(Throwable t) { return new Failure<>(t); } @@ -353,8 +369,8 @@ private Failure(Throwable t) { } @Override - public A orThrow() { - throw throwChecked(t); + public A orThrow(Fn1 fn) throws T { + throw fn.apply(t); } @Override @@ -388,7 +404,7 @@ private Success(A a) { } @Override - public A orThrow() { + public A orThrow(Fn1 fn) { return a; } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index 77425e391..ee6ad0dd7 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -51,7 +51,7 @@ public Subjects> testSubject() { @Test public void catchingWithGenericPredicate() { - Try caught = Try.failure(new RuntimeException()) + Try caught = Try.failure(new RuntimeException()) .catching(__ -> false, r -> "caught first") .catching(__ -> true, r -> "caught second"); @@ -68,7 +68,7 @@ public void catchingIsANoOpForSuccess() { @Test public void firstMatchingCatchBlockWins() { - Try caught = Try.failure(new IllegalStateException()) + Try caught = Try.failure(new IllegalStateException()) .catching(__ -> true, __ -> "first") .catching(__ -> true, __ -> "second"); @@ -77,7 +77,7 @@ public void firstMatchingCatchBlockWins() { @Test public void catchBasedOnExceptionType() { - Try caught = Try.failure(new IllegalStateException()) + Try caught = Try.failure(new IllegalStateException()) .catching(IllegalArgumentException.class, __ -> "illegal argument exception") .catching(IllegalStateException.class, __ -> "illegal state exception") .catching(RuntimeException.class, __ -> "runtime exception"); @@ -114,14 +114,14 @@ public void exceptionThrownInEnsuringBlockIsCaught() { @Test public void forfeitEnsuresFailure() { IllegalStateException expected = new IllegalStateException(); - assertEquals(expected, Try.failure(expected).forfeit(__ -> new IllegalArgumentException())); + assertEquals(expected, Try.failure(expected).forfeit(__ -> new IllegalArgumentException())); assertEquals(expected, Try.success(1).forfeit(__ -> expected)); } @Test public void recoverEnsuresSuccess() { assertEquals((Integer) 1, Try.success(1).recover(constantly(1))); - assertEquals((Integer) 1, Try.failure(new IllegalArgumentException()).recover(constantly(1))); + assertEquals((Integer) 1, Try.failure(new IllegalArgumentException()).recover(constantly(1))); } @Test @@ -233,4 +233,19 @@ public void orThrowCanStillThrowCheckedExceptions() { } catch (Exception expected) { } } + + @Test + public void orThrowCanTransformFirst() { + try { + Try.trying(() -> { + throw new IllegalStateException(); + }).orThrow(IllegalArgumentException::new); + fail("Expected RuntimeException to be thrown, but nothing was"); + } catch (IllegalStateException ioException) { + fail("Expected thrown exception to not be IllegalStateException, but it was"); + } catch (IllegalArgumentException expected) { + } catch (Exception e) { + fail("A different exception altogether was thrown."); + } + } } \ No newline at end of file From 60a7efff751dbe98079cd443e2db2ac07fb9485a Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 14 May 2019 20:00:49 -0500 Subject: [PATCH 158/348] peek now accepts a -> IO for better inference --- .../jnape/palatable/lambda/adt/Either.java | 3 ++- .../com/jnape/palatable/lambda/adt/Maybe.java | 4 +-- .../lambda/functions/builtin/fn2/Peek.java | 17 ++++++------ .../lambda/functions/builtin/fn2/Peek2.java | 27 ++++++++++--------- .../jnape/palatable/lambda/adt/MaybeTest.java | 7 ++--- .../testsupport/assertion/LensAssert.java | 3 ++- .../testsupport/matchers/LeftMatcher.java | 6 ++--- .../testsupport/matchers/RightMatcher.java | 6 ++--- .../testsupport/traits/ApplicativeLaws.java | 6 ++--- .../testsupport/traits/BifunctorLaws.java | 6 ++--- .../java/testsupport/traits/FunctorLaws.java | 6 ++--- .../java/testsupport/traits/MonadLaws.java | 6 ++--- .../testsupport/traits/TraversableLaws.java | 7 +++-- 13 files changed, 54 insertions(+), 50 deletions(-) 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 1148c0523..360043cb6 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -12,6 +12,7 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -176,7 +177,7 @@ public Either peek(Effect effect) { * @param rightEffect the effecting consumer for right values * @return the Either, unaltered */ - public Either peek(Effect leftEffect, Effect rightEffect) { + public Either peek(Fn1> leftEffect, Fn1> rightEffect) { return Peek2.peek2(leftEffect, rightEffect, this); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index 94f4e6bda..2913599a0 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -5,13 +5,13 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -206,7 +206,7 @@ public Choice2 invert() { * @param effect the consumer * @return the same Maybe instance */ - public final Maybe peek(Effect effect) { + public final Maybe peek(Fn1> effect) { return Peek.peek(effect, this); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java index 83a33484d..bea6bb1c5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.io.IO; /** * Given an {@link Effect}, "peek" at the value contained inside a {@link Functor} via {@link Functor#fmap(Fn1)}, @@ -12,7 +13,7 @@ * @param the functor parameter type * @param the functor type */ -public final class Peek> implements Fn2, FA, FA> { +public final class Peek> implements Fn2>, FA, FA> { private static final Peek INSTANCE = new Peek<>(); private Peek() { @@ -20,11 +21,11 @@ private Peek() { @Override @SuppressWarnings("unchecked") - public FA checkedApply(Effect consumer, FA fa) { + public FA checkedApply(Fn1> effect, FA fa) { return (FA) fa.fmap(a -> { - consumer.apply(a).unsafePerformIO(); + effect.apply(a).unsafePerformIO(); return a; - }); + }).coerce(); } @SuppressWarnings("unchecked") @@ -32,11 +33,11 @@ public FA checkedApply(Effect consumer, FA fa) { return (Peek) INSTANCE; } - public static > Fn1 peek(Effect consumer) { - return Peek.peek().apply(consumer); + public static > Fn1 peek(Fn1> effect) { + return Peek.peek().apply(effect); } - public static > FA peek(Effect consumer, FA fa) { - return Peek.peek(consumer).apply(fa); + public static > FA peek(Fn1> effect, FA fa) { + return Peek.peek(effect).apply(fa); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java index 7e3d3c465..3114f26c1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.functions.Fn3; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.BoundedBifunctor; +import com.jnape.palatable.lambda.io.IO; /** * Given two {@link Effect}s, "peek" at the values contained inside a {@link Bifunctor} via @@ -16,7 +17,7 @@ * @param the bifunctor type */ public final class Peek2> implements - Fn3, Effect, FAB, FAB> { + Fn3>, Fn1>, FAB, FAB> { private static final Peek2 INSTANCE = new Peek2<>(); private Peek2() { @@ -24,12 +25,12 @@ private Peek2() { @Override @SuppressWarnings("unchecked") - public FAB checkedApply(Effect aConsumer, Effect bConsumer, FAB fab) { + public FAB checkedApply(Fn1> effectA, Fn1> effectB, FAB fab) { return (FAB) fab.biMap(a -> { - aConsumer.apply(a).unsafePerformIO(); + effectA.apply(a).unsafePerformIO(); return a; }, b -> { - bConsumer.apply(b).unsafePerformIO(); + effectB.apply(b).unsafePerformIO(); return b; }); } @@ -39,21 +40,21 @@ public FAB checkedApply(Effect aConsumer, Effect bConsumer return (Peek2) INSTANCE; } - public static > Fn2, FAB, FAB> - peek2(Effect aConsumer) { - return Peek2.peek2().apply(aConsumer); + public static > + Fn2>, FAB, FAB> peek2(Fn1> effectA) { + return Peek2.peek2().apply(effectA); } public static > Fn1 peek2( - Effect aConsumer, - Effect bConsumer) { - return Peek2.peek2(aConsumer).apply(bConsumer); + Fn1> effectA, + Fn1> effectB) { + return Peek2.peek2(effectA).apply(effectB); } public static > FAB peek2( - Effect aConsumer, - Effect bConsumer, + Fn1> effectA, + Fn1> effectB, FAB fab) { - return Peek2.peek2(aConsumer, bConsumer).apply(fab); + return Peek2.peek2(effectA, effectB).apply(fab); } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java index 281f00cf8..0548e74f4 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java @@ -21,9 +21,10 @@ import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; @@ -98,10 +99,10 @@ public void fromEither() { @Test public void peek() { AtomicInteger ref = new AtomicInteger(0); - assertEquals(just(1), just(1).peek(fromConsumer(__ -> ref.incrementAndGet()))); + assertEquals(just(1), just(1).peek(constantly(io(ref::incrementAndGet)))); assertEquals(1, ref.get()); - assertEquals(nothing(), nothing().peek(fromConsumer(__ -> ref.incrementAndGet()))); + assertEquals(nothing(), nothing().peek(constantly(io(ref::incrementAndGet)))); assertEquals(1, ref.get()); } diff --git a/src/test/java/testsupport/assertion/LensAssert.java b/src/test/java/testsupport/assertion/LensAssert.java index aea73adb5..2c174cada 100644 --- a/src/test/java/testsupport/assertion/LensAssert.java +++ b/src/test/java/testsupport/assertion/LensAssert.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Map; import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.lambda.optics.Optic; @@ -33,7 +34,7 @@ public static void assertLensLawfulness(Optic, Functor< .reduceLeft(asList(falsify("You get back what you put in", (s, b) -> view(lens, set(lens, b, s)), (s, b) -> b, cases), falsify("Putting back what you got changes nothing", (s, b) -> set(lens, view(lens, s), s), (s, b) -> s, cases), falsify("Setting twice is equivalent to setting once", (s, b) -> set(lens, b, set(lens, b, s)), (s, b) -> set(lens, b, s), cases))) - .peek(failures -> {throw new AssertionError("Lens law failures\n\n" + failures);}); + .peek(failures -> IO.throwing(new AssertionError("Lens law failures\n\n" + failures))); } private static Maybe falsify(String label, Fn2 l, Fn2 r, diff --git a/src/test/java/testsupport/matchers/LeftMatcher.java b/src/test/java/testsupport/matchers/LeftMatcher.java index 7ccb74737..fa57261fe 100644 --- a/src/test/java/testsupport/matchers/LeftMatcher.java +++ b/src/test/java/testsupport/matchers/LeftMatcher.java @@ -5,8 +5,8 @@ import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; -import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.io.IO.io; public final class LeftMatcher extends TypeSafeMatcher> { @@ -30,11 +30,11 @@ public void describeTo(Description description) { @Override protected void describeMismatchSafely(Either item, Description mismatchDescription) { mismatchDescription.appendText("was "); - item.peek(fromConsumer(l -> { + item.peek(l -> io(() -> { mismatchDescription.appendText("Left value of "); lMatcher.describeMismatch(l, mismatchDescription); }), - fromConsumer(r -> mismatchDescription.appendValue(item))); + r -> io(() -> mismatchDescription.appendValue(item))); } public static LeftMatcher isLeftThat(Matcher lMatcher) { diff --git a/src/test/java/testsupport/matchers/RightMatcher.java b/src/test/java/testsupport/matchers/RightMatcher.java index 8e4f15c36..cce44fe03 100644 --- a/src/test/java/testsupport/matchers/RightMatcher.java +++ b/src/test/java/testsupport/matchers/RightMatcher.java @@ -5,8 +5,8 @@ import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; -import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.io.IO.io; public final class RightMatcher extends TypeSafeMatcher> { @@ -30,8 +30,8 @@ public void describeTo(Description description) { @Override protected void describeMismatchSafely(Either item, Description mismatchDescription) { mismatchDescription.appendText("was "); - item.peek(fromConsumer(l -> mismatchDescription.appendValue(item)), - fromConsumer(r -> { + item.peek(l -> io(() -> mismatchDescription.appendValue(item)), + r -> io(() -> { mismatchDescription.appendText("Right value of "); rMatcher.describeMismatch(r, mismatchDescription); })); diff --git a/src/test/java/testsupport/traits/ApplicativeLaws.java b/src/test/java/testsupport/traits/ApplicativeLaws.java index e449fe603..1d5c0904f 100644 --- a/src/test/java/testsupport/traits/ApplicativeLaws.java +++ b/src/test/java/testsupport/traits/ApplicativeLaws.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; @@ -30,9 +31,8 @@ public void test(Applicative applicative) { this::testDiscardR, this::testLazyZip) ) - .peek(s -> { - throw new AssertionError("The following Applicative laws did not hold for instance of " + applicative.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Applicative laws did not hold for instance of " + + applicative.getClass() + ": \n\t - " + s))); } private Maybe testIdentity(Applicative applicative) { diff --git a/src/test/java/testsupport/traits/BifunctorLaws.java b/src/test/java/testsupport/traits/BifunctorLaws.java index 780519c17..d682435e6 100644 --- a/src/test/java/testsupport/traits/BifunctorLaws.java +++ b/src/test/java/testsupport/traits/BifunctorLaws.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; @@ -22,9 +23,8 @@ public void test(Bifunctor bifunctor) { this::testRightIdentity, this::testMutualIdentity) ) - .peek(s -> { - throw new AssertionError("The following Bifunctor laws did not hold for instance of " + bifunctor.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Bifunctor laws did not hold for instance of " + + bifunctor.getClass() + ": \n\t - " + s))); } private Maybe testLeftIdentity(Bifunctor bifunctor) { diff --git a/src/test/java/testsupport/traits/FunctorLaws.java b/src/test/java/testsupport/traits/FunctorLaws.java index 13ad2b423..5fc7d5937 100644 --- a/src/test/java/testsupport/traits/FunctorLaws.java +++ b/src/test/java/testsupport/traits/FunctorLaws.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; @@ -21,9 +22,8 @@ public void test(Functor f) { fn -> fn.apply(f), asList(this::testIdentity, this::testComposition)) - .peek(s -> { - throw new AssertionError("The following Functor laws did not hold for instance of " + f.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Functor laws did not hold for instance of " + + f.getClass() + ": \n\t - " + s))); } private Maybe testIdentity(Functor f) { diff --git a/src/test/java/testsupport/traits/MonadLaws.java b/src/test/java/testsupport/traits/MonadLaws.java index 6a2df2392..2ff5a6e77 100644 --- a/src/test/java/testsupport/traits/MonadLaws.java +++ b/src/test/java/testsupport/traits/MonadLaws.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.traitor.traits.Trait; @@ -24,9 +25,8 @@ public void test(Monad m) { this::testRightIdentity, this::testAssociativity, this::testJoin)) - .peek(s -> { - throw new AssertionError("The following Monad laws did not hold for instance of " + m.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Monad laws did not hold for instance of " + + m.getClass() + ": \n\t - " + s))); } private Maybe testLeftIdentity(Monad m) { diff --git a/src/test/java/testsupport/traits/TraversableLaws.java b/src/test/java/testsupport/traits/TraversableLaws.java index f27eca241..c0a6c4968 100644 --- a/src/test/java/testsupport/traits/TraversableLaws.java +++ b/src/test/java/testsupport/traits/TraversableLaws.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.lambda.traversable.Traversable; import com.jnape.palatable.traitor.traits.Trait; @@ -28,10 +29,8 @@ public void test(Traversable traversable) { this::testIdentity, this::testComposition) ) - .peek(s -> { - throw new AssertionError("The following Traversable laws did not hold for instance of " - + traversable.getClass() + ": \n\t - " + s); - }); + .peek(s -> IO.throwing(new AssertionError("The following Traversable laws did not hold for instance of " + + traversable.getClass() + ": \n\t - " + s))); } private Maybe testNaturality(Traversable trav) { From a6636d5c23451ff50dd9d7678024b495dbdf1dbb Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 15 May 2019 17:46:40 -0500 Subject: [PATCH 159/348] Renaming current fn2 sfm to curried, and new fn2 just aids inference --- .../com/jnape/palatable/lambda/functions/Fn1.java | 6 +++--- .../com/jnape/palatable/lambda/functions/Fn2.java | 13 +++++++++---- .../jnape/palatable/lambda/monoid/builtin/Endo.java | 4 ++-- .../java/com/jnape/palatable/lambda/optics/Iso.java | 2 +- .../lambda/optics/lenses/IterableLens.java | 4 ++-- .../palatable/lambda/traversable/LambdaMap.java | 4 ++-- .../jnape/palatable/lambda/functions/Fn2Test.java | 10 ++++++++-- 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index fcf44bd69..d08195f42 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -12,7 +12,7 @@ import java.util.function.Function; -import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** @@ -69,7 +69,7 @@ default Fn0 thunk(A a) { * @return the widened function */ default Fn2 widen() { - return fn2(constantly(this)); + return curried(constantly(this)); } /** @@ -246,7 +246,7 @@ default Fn1 contraMap(Fn1 fn) { * @return an {@link Fn2}<Y, Z, B> */ default Fn2 compose(Fn2 before) { - return fn2(before.fmap(this::contraMap))::apply; + return curried(before.fmap(this::contraMap))::apply; } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index 769f0a4d1..f0e138ec5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -100,7 +100,7 @@ default BiFunction toBiFunction() { */ @Override default Fn2 discardR(Applicative> appB) { - return fn2(Fn1.super.discardR(appB)); + return curried(Fn1.super.discardR(appB)); } /** @@ -108,7 +108,7 @@ default Fn2 discardR(Applicative> appB) { */ @Override default Fn2 diMapL(Fn1 fn) { - return fn2(Fn1.super.diMapL(fn)); + return curried(Fn1.super.diMapL(fn)); } /** @@ -116,7 +116,7 @@ default Fn2 diMapL(Fn1 fn) { */ @Override default Fn2 contraMap(Fn1 fn) { - return fn2(Fn1.super.contraMap(fn)); + return curried(Fn1.super.contraMap(fn)); } /** @@ -149,7 +149,12 @@ static Fn2 fromBiFunction(BiFunction the output type * @return the {@link Fn2} */ - static Fn2 fn2(Fn1> curriedFn1) { + static Fn2 curried(Fn1> curriedFn1) { return (a, b) -> curriedFn1.apply(a).apply(b); } + + static Fn2 fn2(Fn2 fn2) { + return fn2; + } + } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java index 75a4090ba..990689535 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Endo.java @@ -4,7 +4,7 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.monoid.Monoid; -import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; /** @@ -35,7 +35,7 @@ public Fn1 checkedApply(Fn1 f, Fn1 g) { @Override public Fn2, A, A> apply(Fn1 f) { - return fn2(Monoid.super.apply(f)); + return curried(Monoid.super.apply(f)); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java index 11fdd4345..feb59212c 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -137,7 +137,7 @@ default Iso discardR(Applicative> appB) { @Override default Iso flatMap(Fn1>> fn) { //noinspection RedundantTypeArguments - return unIso().fmap(bt -> Fn2.fn2( + return unIso().fmap(bt -> Fn2.curried( fn1(bt.fmap(fn.>fmap(Monad>::coerce)) .fmap(Iso::unIso) .fmap(Tuple2::_2) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java index b0bd8e810..b0f125c14 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/IterableLens.java @@ -6,7 +6,7 @@ import com.jnape.palatable.lambda.optics.Iso; import com.jnape.palatable.lambda.optics.Lens; -import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; @@ -45,7 +45,7 @@ public static Lens.Simple, Maybe> head() { * @return a lens focusing on the tail of an {@link Iterable} */ public static Lens.Simple, Iterable> tail() { - return simpleLens(Tail::tail, fn2(Head.head().fmap(o -> o.fmap(cons()).orElse(id())))); + return simpleLens(Tail::tail, curried(Head.head().fmap(o -> o.fmap(cons()).orElse(id())))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java index 94a2e2e7c..81f6dd953 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java @@ -10,7 +10,7 @@ import java.util.Objects; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; import static com.jnape.palatable.lambda.functions.builtin.fn2.ToMap.toMap; @@ -50,7 +50,7 @@ public LambdaMap fmap(Fn1 fn) { AppC extends Applicative, AppTrav extends Applicative> AppTrav traverse(Fn1 fn, Fn1 pure) { - return foldLeft(fn2(appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> { + return foldLeft(curried(appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> { ((LambdaMap) m).unwrap().put(k, v); return m; })))), diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java index dbe1d5b7a..71e3a65e3 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java @@ -36,9 +36,15 @@ public void toBiFunction() { } @Test - public void fn2() { + public void curried() { Fn1> curriedFn1 = (x) -> (y) -> String.format(x, y); - assertEquals("foo bar", Fn2.fn2(curriedFn1).apply("foo %s", "bar")); + assertEquals("foo bar", Fn2.curried(curriedFn1).apply("foo %s", "bar")); + } + + @Test + public void fn2() { + Fn2 fn2 = Fn2.fn2(String::format); + assertEquals("foo bar", fn2.apply("foo %s", "bar")); } @Test From 8cf4050d971b6b49dd33a2217ff4424ab11408cb Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 15 May 2019 17:52:27 -0500 Subject: [PATCH 160/348] Effect#andThen for right-to-left composition of effects --- .../com/jnape/palatable/lambda/functions/Effect.java | 10 ++++++++++ .../jnape/palatable/lambda/functions/EffectTest.java | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 6e23e2932..fd135aa25 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -46,6 +46,16 @@ default IO apply(A a) { } } + /** + * Left-to-right composition of {@link Effect Effects}. + * + * @param effect the other {@link Effect} + * @return the composed {@link Effect} + */ + default Effect andThen(Effect effect) { + return a -> apply(a).flatMap(constantly(effect.apply(a))); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java index c0a442762..49554fae3 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java @@ -13,6 +13,8 @@ import static com.jnape.palatable.lambda.functions.Effect.effect; import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.specialized.SideEffect.sideEffect; +import static com.jnape.palatable.lambda.io.IO.io; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; @@ -36,6 +38,15 @@ public void covariantReturns() { assertEquals(asList("1", "2", "3", "4"), results); } + @Test + public void andThen() { + AtomicInteger counter = new AtomicInteger(); + Effect inc = c -> io(sideEffect(c::incrementAndGet)); + + inc.andThen(inc).apply(counter).unsafePerformIO(); + assertEquals(2, counter.get()); + } + @Test public void staticFactoryMethods() { AtomicInteger counter = new AtomicInteger(); From 03065e915731bb310ff800d2c0966bbff4dd94bc Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 15 May 2019 18:16:24 -0500 Subject: [PATCH 161/348] Adding javadoc --- .../java/com/jnape/palatable/lambda/functions/Fn2.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index f0e138ec5..0528ff71a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -153,8 +153,16 @@ static Fn2 curried(Fn1> curriedFn1) { return (a, b) -> curriedFn1.apply(a).apply(b); } + /** + * Static method to aid inference. + * + * @param fn2 the {@link Fn2} + * @param the first input type + * @param the second input type + * @param the output type + * @return the {@link Fn2} + */ static Fn2 fn2(Fn2 fn2) { return fn2; } - } From 44e7f2220cdc22549bad3ef4afab37b44e6c321d Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 16 May 2019 18:00:01 -0500 Subject: [PATCH 162/348] Effect#noop allows custom parametricity --- .../java/com/jnape/palatable/lambda/functions/Effect.java | 4 ++-- .../com/jnape/palatable/lambda/functions/EffectTest.java | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index fd135aa25..077935f49 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -97,7 +97,7 @@ static Effect fromConsumer(Consumer consumer) { * @param sideEffect the {@link SideEffect} * @return the {@link Effect} */ - static Effect effect(SideEffect sideEffect) { + static Effect effect(SideEffect sideEffect) { return effect(constantly(io(sideEffect))); } @@ -108,7 +108,7 @@ static Effect effect(SideEffect sideEffect) { */ @SuppressWarnings("unused") static Effect noop() { - return effect(NOOP).contraMap(constantly(UNIT)); + return effect(NOOP); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java index 49554fae3..0609643f5 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java @@ -9,7 +9,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; -import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.Effect.effect; import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -51,8 +50,8 @@ public void andThen() { public void staticFactoryMethods() { AtomicInteger counter = new AtomicInteger(); - Effect runnableEffect = effect(counter::incrementAndGet); - runnableEffect.apply(UNIT).unsafePerformIO(); + Effect sideEffect = effect(counter::incrementAndGet); + sideEffect.apply("foo").unsafePerformIO(); assertEquals(1, counter.get()); Effect fnEffect = Effect.fromConsumer(AtomicInteger::incrementAndGet); From 5a2ae62963bf23291a0ba9df07903a0d55560021 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 17 May 2019 00:03:53 -0500 Subject: [PATCH 163/348] Either#peek only requires Fn1 --- src/main/java/com/jnape/palatable/lambda/adt/Either.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 360043cb6..0fe24612f 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -2,7 +2,6 @@ import com.jnape.palatable.lambda.adt.choice.Choice3; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; -import com.jnape.palatable.lambda.functions.Effect; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; @@ -166,7 +165,7 @@ public final Either merge(Fn2 leftFn, * @param effect the effecting consumer * @return the Either, unaltered */ - public Either peek(Effect effect) { + public Either peek(Fn1> effect) { return Peek.peek(effect, this); } From 6f30dee6d9352fef8af4088eb3945b0d5b2d16c9 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 17 May 2019 18:53:05 -0500 Subject: [PATCH 164/348] Traversable#traverse requires one less type parameter --- src/main/java/com/jnape/palatable/lambda/adt/Either.java | 3 +-- src/main/java/com/jnape/palatable/lambda/adt/Maybe.java | 3 +-- src/main/java/com/jnape/palatable/lambda/adt/These.java | 4 ++-- src/main/java/com/jnape/palatable/lambda/adt/Try.java | 3 +-- .../java/com/jnape/palatable/lambda/adt/choice/Choice2.java | 3 +-- .../java/com/jnape/palatable/lambda/adt/choice/Choice3.java | 3 +-- .../java/com/jnape/palatable/lambda/adt/choice/Choice4.java | 3 +-- .../java/com/jnape/palatable/lambda/adt/choice/Choice5.java | 3 +-- .../java/com/jnape/palatable/lambda/adt/choice/Choice6.java | 3 +-- .../java/com/jnape/palatable/lambda/adt/choice/Choice7.java | 3 +-- .../java/com/jnape/palatable/lambda/adt/choice/Choice8.java | 3 +-- .../jnape/palatable/lambda/adt/hlist/SingletonHList.java | 3 +-- .../java/com/jnape/palatable/lambda/adt/hlist/Tuple2.java | 6 +++--- .../java/com/jnape/palatable/lambda/adt/hlist/Tuple3.java | 6 +++--- .../java/com/jnape/palatable/lambda/adt/hlist/Tuple4.java | 6 +++--- .../java/com/jnape/palatable/lambda/adt/hlist/Tuple5.java | 6 +++--- .../java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java | 6 +++--- .../java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java | 6 +++--- .../java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java | 6 +++--- .../lambda/functions/recursion/RecursiveResult.java | 3 +-- .../com/jnape/palatable/lambda/functor/builtin/Const.java | 3 +-- .../jnape/palatable/lambda/functor/builtin/Identity.java | 3 +-- .../com/jnape/palatable/lambda/functor/builtin/Lazy.java | 3 +-- .../jnape/palatable/lambda/traversable/LambdaIterable.java | 3 +-- .../com/jnape/palatable/lambda/traversable/LambdaMap.java | 5 ++--- .../com/jnape/palatable/lambda/traversable/Traversable.java | 5 ++--- 26 files changed, 43 insertions(+), 61 deletions(-) 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 0fe24612f..29e421570 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -282,8 +282,7 @@ public final Either discardR(Applicative> appB) { @Override @SuppressWarnings("unchecked") public final , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return (AppTrav) match(l -> pure.apply((TravB) left(l)), r -> fn.apply(r).fmap(Either::right)); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index 2913599a0..4cc726673 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -213,8 +213,7 @@ public final Maybe peek(Fn1> effect) { @Override @SuppressWarnings("unchecked") public final , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(__ -> pure.apply((TravB) Maybe.nothing()), a -> (AppTrav) fn.apply(a).fmap(Maybe::just)); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index 039b149fd..5f8e67270 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -62,8 +62,8 @@ public final These pure(C c) { @Override @SuppressWarnings("unchecked") public , TravB extends Traversable>, - AppB extends Applicative, AppTrav extends Applicative> - AppTrav traverse(Fn1 fn, Fn1 pure) { + AppTrav extends Applicative> + AppTrav traverse(Fn1> fn, Fn1 pure) { return match(a -> pure.apply((TravB) a(a)), b -> fn.apply(b).fmap(this::pure).fmap(Applicative::coerce).coerce(), into((a, b) -> fn.apply(b).fmap(c -> both(a, c)).fmap(Applicative::coerce).coerce())); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index 00b629a72..40a678339 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -224,8 +224,7 @@ public Try discardR(Applicative> appB) { @Override @SuppressWarnings("unchecked") public , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(t -> pure.apply((TravB) failure(t)), a -> fn.apply(a).fmap(Try::success).fmap(Applicative::coerce).coerce()); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index 24cc10bc5..7366881c2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -151,8 +151,7 @@ public final Choice2 flatMap(Fn1, TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(a -> pure.apply((TravB) a(a)), b -> fn.apply(b).>fmap(Choice2::b).fmap(Functor::coerce).coerce()); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 0b58ca14f..5e4388419 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -152,8 +152,7 @@ public Choice3 flatMap(Fn1, TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(a -> pure.apply((TravB) Choice3.a(a)).coerce(), b -> pure.apply((TravB) Choice3.b(b)).coerce(), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index a93eae6cd..4f79f3d5e 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -152,8 +152,7 @@ public Choice4 flatMap(Fn1, TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(a -> pure.apply((TravB) Choice4.a(a)).coerce(), b -> pure.apply((TravB) Choice4.b(b)).coerce(), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index e3e4a7958..8714e4395 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -156,8 +156,7 @@ public Choice5 flatMap(Fn1, TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(a -> pure.apply((TravB) Choice5.a(a)).coerce(), b -> pure.apply((TravB) Choice5.b(b)).coerce(), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index dd788fb5b..ff2ba8df5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -161,8 +161,7 @@ public Choice6 flatMap(Fn1, TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(a -> pure.apply((TravB) Choice6.a(a)).coerce(), b -> pure.apply((TravB) Choice6.b(b)).coerce(), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index a72489ecb..590796133 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -163,8 +163,7 @@ public Choice7 flatMap( @Override @SuppressWarnings("unchecked") public , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(a -> pure.apply((TravB) Choice7.a(a)).coerce(), b -> pure.apply((TravB) Choice7.b(b)).coerce(), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index 2d21f27ba..cfdb71587 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -157,8 +157,7 @@ public Choice8 flatMap( @Override @SuppressWarnings("unchecked") public , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(a -> pure.apply((TravB) Choice8.a(a)).coerce(), b -> pure.apply((TravB) Choice8.b(b)).coerce(), diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index ca8f76b5c..176745aba 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -70,8 +70,7 @@ public <_1Prime> SingletonHList<_1Prime> flatMap(Fn1, TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return fn.apply(head()).fmap(SingletonHList::new).fmap(Applicative::coerce).coerce(); } 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 afb1d9e95..78bf332c3 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 @@ -133,9 +133,9 @@ public <_2Prime> Tuple2<_1, _2Prime> flatMap(Fn1, TravB extends Traversable<_2Prime, Tuple2<_1, ?>>, - AppB extends Applicative<_2Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, - Fn1 pure) { + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_2).fmap(_2Prime -> fmap(constantly(_2Prime))).fmap(Applicative::coerce).coerce(); } 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 01ed4cf6c..0e99a88b9 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 @@ -135,9 +135,9 @@ public <_3Prime> Tuple3<_1, _2, _3Prime> flatMap( @Override public <_3Prime, App extends Applicative, TravB extends Traversable<_3Prime, Tuple3<_1, _2, ?>>, - AppB extends Applicative<_3Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, - Fn1 pure) { + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_3).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } 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 90a1d3ec6..1e99d3fd5 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 @@ -150,9 +150,9 @@ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> flatMap( @Override public <_4Prime, App extends Applicative, TravB extends Traversable<_4Prime, Tuple4<_1, _2, _3, ?>>, - AppB extends Applicative<_4Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, - Fn1 pure) { + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_4).fmap(_4Prime -> fmap(constantly(_4Prime))).fmap(Applicative::coerce).coerce(); } 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 2e321fbae..0292831d2 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 @@ -170,9 +170,9 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> flatMap( @Override public <_5Prime, App extends Applicative, TravB extends Traversable<_5Prime, Tuple5<_1, _2, _3, _4, ?>>, - AppB extends Applicative<_5Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, - Fn1 pure) { + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_5).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 4ec22546b..86991a8ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -191,9 +191,9 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> flatMap( @Override public <_6Prime, App extends Applicative, TravB extends Traversable<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>, - AppB extends Applicative<_6Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, - Fn1 pure) { + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_6).fmap(_6Prime -> fmap(constantly(_6Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index e42cc4968..60d42664c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -212,9 +212,9 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> flatMap( @Override public <_7Prime, App extends Applicative, TravB extends Traversable<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, - AppB extends Applicative<_7Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, - Fn1 pure) { + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_7).fmap(_7Prime -> fmap(constantly(_7Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index e9db4aba9..81054635e 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -232,9 +232,9 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> flatMap( @Override public <_8Prime, App extends Applicative, TravB extends Traversable<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, - AppB extends Applicative<_8Prime, App>, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, - Fn1 pure) { + AppTrav extends Applicative> AppTrav traverse( + Fn1> fn, + Fn1 pure) { return fn.apply(_8).fmap(_8Prime -> fmap(constantly(_8Prime))).fmap(Applicative::coerce).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java index 29ddc08c8..c21c62908 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java @@ -78,8 +78,7 @@ public RecursiveResult discardR(Applicative> @Override public , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return match(__ -> pure.apply(coerce()), b -> fn.apply(b).fmap(this::pure).fmap(RecursiveResult::coerce).coerce()); diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index 279d04595..73e974ede 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -103,8 +103,7 @@ public Const flatMap(Fn1>> f */ @Override public , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return pure.apply(coerce()); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java index bb298596c..dba617294 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java @@ -92,8 +92,7 @@ public Identity discardR(Applicative> appB) { @Override @SuppressWarnings("unchecked") public , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return (AppTrav) fn.apply(runIdentity()).fmap(Identity::new); } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java index c79a4c0c7..fff6acc72 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java @@ -50,8 +50,7 @@ public Lazy flatMap(Fn1>> f) { @Override @SuppressWarnings("unchecked") public , TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return fn.apply(value()).fmap(b -> (TravB) lazy(b)).coerce(); } 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 b59ccfcc4..6fe5f4a38 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -112,8 +112,7 @@ public LambdaIterable flatMap(Fn1, TravB extends Traversable>, - AppB extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return FoldRight.foldRight( (a, lglb) -> fn.apply(a) diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java index 81f6dd953..f8e8c7fd2 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java @@ -47,15 +47,14 @@ public LambdaMap fmap(Fn1 fn) { @Override @SuppressWarnings("unchecked") public , TravC extends Traversable>, - AppC extends Applicative, - AppTrav extends Applicative> AppTrav traverse(Fn1 fn, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return foldLeft(curried(appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> { ((LambdaMap) m).unwrap().put(k, v); return m; })))), pure.apply((TravC) LambdaMap.wrap(new HashMap<>())), - this.fmap(fn).unwrap().entrySet()); + this.fmap(fn).unwrap().entrySet()); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java index 91d0a66c6..d9f24621c 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java @@ -38,15 +38,14 @@ public interface Traversable> extends Functor the resulting element type * @param the result applicative type * @param this Traversable instance over B - * @param the result applicative instance over B * @param the full inferred resulting type from the traversal * @param fn the function to apply * @param pure the applicative pure function * @return the traversed Traversable, wrapped inside an applicative */ - , TravB extends Traversable, AppB extends Applicative, + , TravB extends Traversable, AppTrav extends Applicative> AppTrav traverse( - Fn1 fn, Fn1 pure); + Fn1> fn, Fn1 pure); @Override default Traversable fmap(Fn1 fn) { From a929f92a5affec62cc3e4afaa5db86b60b95d2aa Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 17 May 2019 19:02:50 -0500 Subject: [PATCH 165/348] Sequence#sequence requires 2 fewer type parameters --- .../functions/builtin/fn2/Sequence.java | 66 ++++++++----------- .../functions/builtin/fn2/SequenceTest.java | 5 ++ 2 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java index 2237966c3..bed18e1aa 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Sequence.java @@ -24,82 +24,72 @@ * @param the Traversable element type * @param the Applicative unification parameter * @param the Traversable unification parameter - * @param the Applicative instance wrapped in the input Traversable * @param the Traversable instance wrapped in the output Applicative * @param the concrete parametrized output Applicative type - * @param the concrete parametrized input Traversable type */ public final class Sequence, Trav extends Traversable, - AppA extends Applicative, TravA extends Traversable, - AppTrav extends Applicative, - TravApp extends Traversable> implements Fn2, AppTrav> { + AppTrav extends Applicative> implements + Fn2, Trav>, Fn1, AppTrav> { - private static final Sequence INSTANCE = new Sequence<>(); + private static final Sequence INSTANCE = new Sequence<>(); private Sequence() { } @Override - public AppTrav checkedApply(TravApp traversable, Fn1 pure) { + public AppTrav checkedApply(Traversable, Trav> traversable, + Fn1 pure) { return traversable.traverse(id(), pure); } @SuppressWarnings("unchecked") public static , Trav extends Traversable, - AppA extends Applicative, TravA extends Traversable, - AppTrav extends Applicative, - TravApp extends Traversable> Sequence sequence() { - return (Sequence) INSTANCE; + AppTrav extends Applicative> Sequence sequence() { + return (Sequence) INSTANCE; } public static , Trav extends Traversable, - AppA extends Applicative, TravA extends Traversable, - AppTrav extends Applicative, - TravApp extends Traversable> Fn1, AppTrav> sequence( - TravApp traversable) { - return Sequence.sequence().apply(traversable); + AppTrav extends Applicative> Fn1, AppTrav> sequence( + Traversable, Trav> traversable) { + return Sequence.sequence().apply(traversable); } public static , Trav extends Traversable, TravA extends Traversable, - AppA extends Applicative, - AppTrav extends Applicative, - TravApp extends Traversable> AppTrav sequence(TravApp traversable, - Fn1 pure) { - return Sequence.sequence(traversable).apply(pure); + AppTrav extends Applicative> AppTrav sequence( + Traversable, Trav> traversable, + Fn1 pure) { + return Sequence.sequence(traversable).apply(pure); } @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) - public static , AppA extends Applicative, - AppIterable extends Applicative, App>, - IterableApp extends Iterable> - Fn1, ? extends AppIterable>, AppIterable> sequence(IterableApp iterableApp) { - return pure -> (AppIterable) Sequence., LambdaIterable, AppA, Applicative, App>, LambdaIterable>sequence( + public static , AppIterable extends Applicative, App>> + Fn1, ? extends AppIterable>, AppIterable> sequence( + Iterable> iterableApp) { + return pure -> (AppIterable) Sequence., LambdaIterable, Applicative, App>>sequence( LambdaIterable.wrap(iterableApp), x -> pure.apply(x.unwrap()).fmap(LambdaIterable::wrap)) .fmap(LambdaIterable::unwrap); } - public static , AppA extends Applicative, - AppIterable extends Applicative, App>, IterableApp extends Iterable> - AppIterable sequence(IterableApp iterableApp, Fn1, ? extends AppIterable> pure) { - return Sequence.sequence(iterableApp).apply(pure); + public static , AppIterable extends Applicative, App>> + AppIterable sequence(Iterable> iterableApp, + Fn1, ? extends AppIterable> pure) { + return Sequence.sequence(iterableApp).apply(pure); } @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) - public static , AppB extends Applicative, - AppMap extends Applicative, App>, MapApp extends Map> - Fn1, ? extends AppMap>, AppMap> sequence(MapApp mapApp) { - return pure -> (AppMap) Sequence., LambdaMap, AppB, Applicative, App>, LambdaMap>sequence( + public static , AppMap extends Applicative, App>> + Fn1, ? extends AppMap>, AppMap> sequence(Map> mapApp) { + return pure -> (AppMap) Sequence., LambdaMap, Applicative, App>>sequence( LambdaMap.wrap(mapApp), x -> pure.apply(x.unwrap()).fmap(LambdaMap::wrap)) .fmap(LambdaMap::unwrap); } - public static , AppB extends Applicative, - AppMap extends Applicative, App>, MapApp extends Map> - AppMap sequence(MapApp mapApp, Fn1, ? extends AppMap> pure) { - return Sequence.sequence(mapApp).apply(pure); + public static , AppMap extends Applicative, App>> + AppMap sequence(Map> mapApp, Fn1, ? extends AppMap> pure) { + return Sequence.sequence(mapApp).apply(pure); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java index b2e65864e..cec572406 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SequenceTest.java @@ -7,6 +7,8 @@ import com.jnape.palatable.lambda.functor.builtin.Identity; import org.junit.Test; +import java.util.Map; + import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; @@ -68,5 +70,8 @@ public void compilation() { Maybe> d = sequence(asList(just(1), just(2)), Maybe::just); assertThat(d.orElseThrow(AssertionError::new), iterates(1, 2)); + + Either> e = sequence(singletonMap("foo", right(1)), Either::right); + assertEquals(right(singletonMap("foo", 1)), e); } } \ No newline at end of file From bbb97ae97f80cf558afe74bcc89a8384f3596aff Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 18:36:08 -0500 Subject: [PATCH 166/348] Prism is a Monad; ProtoOptic offers implicit Profunctor/Identity optic --- .../jnape/palatable/lambda/optics/Prism.java | 108 +++++++++++++++--- .../palatable/lambda/optics/ProtoOptic.java | 16 ++- .../palatable/lambda/optics/PrismTest.java | 14 +++ 3 files changed, 119 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java index d83f01774..f90635c63 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -7,16 +7,27 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cocartesian; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.functor.builtin.Market; +import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.optics.functions.Matching; import com.jnape.palatable.lambda.optics.functions.Pre; import com.jnape.palatable.lambda.optics.functions.Re; import com.jnape.palatable.lambda.optics.functions.View; +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; +import static com.jnape.palatable.lambda.optics.Prism.Simple.adapt; +import static com.jnape.palatable.lambda.optics.functions.Matching.matching; +import static com.jnape.palatable.lambda.optics.functions.Re.re; + /** * Prisms are {@link Iso Isos} that can fail in one direction. Example: *
@@ -42,10 +53,23 @@
  * @param  the input that guarantees its output
  */
 @FunctionalInterface
-public interface Prism extends
-        ProtoOptic, S, T, A, B>,
-        Optic, Identity, S, T, A, B> {
+public interface Prism extends ProtoOptic, S, T, A, B>, Monad> {
 
+    /**
+     * Recover the two mappings encapsulated by this {@link Prism} by sending it through a {@link Market}.
+     *
+     * @return a {@link Tuple2 tuple} of the two mappings encapsulated by this {@link Prism}
+     */
+    default Tuple2, Fn1>> unPrism() {
+        return Tuple2.fill(this., Identity, Identity, Identity,
+                Market>, Market>>apply(
+                new Market<>(Identity::new, Either::right)).fmap(Identity::runIdentity))
+                .biMap(Market::bt, Market::sta);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     @Override
     default >,
             CoF extends Functor>,
@@ -58,15 +82,62 @@ public interface Prism extends
     }
 
     /**
-     * Recover the two mappings encapsulated by this {@link Prism} by sending it through a {@link Market}.
-     *
-     * @return a {@link Tuple2 tuple} of the two mappings encapsulated by this {@link Prism}
+     * {@inheritDoc}
      */
-    default Tuple2, Fn1>> unPrism() {
-        return Tuple2.fill(this., Identity, Identity, Identity,
-                Market>, Market>>apply(
-                new Market<>(Identity::new, Either::right)).fmap(Identity::runIdentity))
-                .biMap(Market::bt, Market::sta);
+    @Override
+    default  Prism pure(U u) {
+        return prism(constantly(left(u)), constantly(u));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    default  Prism flatMap(Fn1>> f) {
+        return unPrism().into((bt, seta) -> prism(
+                s -> seta.apply(s).match(t -> matching(f.apply(t).>coerce(), s), Either::right),
+                b -> View.view(re(f.apply(bt.apply(b)).coerce())).apply(b)));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    default  Prism fmap(Fn1 fn) {
+        return Monad.super.fmap(fn).coerce();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    default  Prism zip(Applicative, Prism> appFn) {
+        return Monad.super.zip(appFn).coerce();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    default  Lazy> lazyZip(
+            Lazy, Prism>> lazyAppFn) {
+        return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    default  Prism discardL(Applicative> appB) {
+        return Monad.super.discardL(appB).coerce();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    default  Prism discardR(Applicative> appB) {
+        return Monad.super.discardR(appB).coerce();
     }
 
     /**
@@ -85,8 +156,7 @@ static  Prism prism(Fn1 bt) {
         return new Prism() {
             @Override
-            public > Optic, F, S, T, A, B> toOptic(
-                    Pure pure) {
+            public > Optic, F, S, T, A, B> toOptic(Pure pure) {
                 return Optic.,
                         F,
                         S, T, A, B,
@@ -113,8 +183,7 @@ static  Prism prism(Fn1 Prism prism(ProtoOptic, S, T, A, B> protoOptic) {
         return new Prism() {
             @Override
-            public > Optic, F, S, T, A, B> toOptic(
-                    Pure pure) {
+            public > Optic, F, S, T, A, B> toOptic(Pure pure) {
                 Optic, F, S, T, A, B> optic = protoOptic.toOptic(pure);
                 return Optic.reframe(optic);
             }
@@ -138,8 +207,7 @@ static  Prism prism(
             Optic, ? super Functor, S, T, A, B> optic) {
         return new Prism() {
             @Override
-            public > Optic, F, S, T, A, B> toOptic(
-                    Pure pure) {
+            public > Optic, F, S, T, A, B> toOptic(Pure pure) {
                 return Optic.reframe(optic);
             }
         };
@@ -160,6 +228,12 @@ static  Prism.Simple simplePrism(Fn1>
         return Prism.prism(s -> sMaybeA.apply(s).toEither(() -> s), as)::toOptic;
     }
 
+
+    static  Prism.Simple fromPartial(Fn1 partialSa,
+                                                 Fn1 as) {
+        return adapt(prism(partialSa.diMap(downcast(), upcast()).choose(), as));
+    }
+
     /**
      * A convenience type with a simplified type signature for common {@link Prism prism} with unified S/T
      * and A/B types.
diff --git a/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java b/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java
index 1d38ef807..57fc5ffbc 100644
--- a/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java
+++ b/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java
@@ -1,8 +1,10 @@
 package com.jnape.palatable.lambda.optics;
 
 import com.jnape.palatable.lambda.functions.specialized.Pure;
+import com.jnape.palatable.lambda.functor.Applicative;
 import com.jnape.palatable.lambda.functor.Functor;
 import com.jnape.palatable.lambda.functor.Profunctor;
+import com.jnape.palatable.lambda.functor.builtin.Identity;
 
 /**
  * A generic supertype representation for a profunctor {@link Optic} that requires a {@link Pure} implementation to
@@ -14,7 +16,9 @@
  * @param  the left side of the input profunctor
  * @param  the right side's functor embedding of the input profunctor
  */
-public interface ProtoOptic

, S, T, A, B> { +@FunctionalInterface +public interface ProtoOptic

, S, T, A, B> + extends Optic, S, T, A, B> { /** * Given a {@link Pure} lifting function, fix this {@link ProtoOptic} to the given {@link Functor} and promote it to @@ -24,5 +28,13 @@ public interface ProtoOptic

, S, T, A, B> * @param the {@link Functor} bound * @return the {@link Optic} */ - > Optic toOptic(Pure pure); + > Optic toOptic(Pure pure); + + @Override + default , CoF extends Functor>, + FB extends Functor, FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return toOptic(Pure.>pure(Identity::new)).apply(pafb); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java index 81b74b14e..b2080bb0b 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java @@ -3,7 +3,14 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; @@ -16,10 +23,17 @@ import static com.jnape.palatable.lambda.optics.functions.View.view; import static org.junit.Assert.assertEquals; +@RunWith(Traits.class) public class PrismTest { private static final Fn1 PARSE_INT = Fn1.fn1(Integer::parseInt); + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public EquatableM, String> testSubject() { + return new EquatableM<>(Prism.fromPartial(Integer::parseInt, Object::toString), + prism -> matching(prism, "foo")); + } + @Test public void prismLaws() { Prism prism = prism(PARSE_INT.choose(), Object::toString); From a1ba4b7c9015ba14c1dfa70ecc9c7cbb7a56efd8 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 18:36:40 -0500 Subject: [PATCH 167/348] EitherLens#left/right prefixed with underscore to avoid future ambiguity --- .../jnape/palatable/lambda/optics/lenses/EitherLens.java | 6 +++--- .../palatable/lambda/optics/lenses/EitherLensTest.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java index 0aa4b86a3..8463d0eb1 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/EitherLens.java @@ -8,7 +8,7 @@ import static com.jnape.palatable.lambda.optics.Lens.simpleLens; /** - * Lenses that operate on {@link Either}s. + * Lenses for {@link Either}. */ public final class EitherLens { @@ -26,7 +26,7 @@ private EitherLens() { * @param the right parameter type * @return a lens that focuses on right values */ - public static Lens.Simple, Maybe> right() { + public static Lens.Simple, Maybe> _right() { return simpleLens(CoProduct2::projectB, (lOrR, maybeR) -> maybeR.>fmap(Either::right).orElse(lOrR)); } @@ -41,7 +41,7 @@ public static Lens.Simple, Maybe> right() { * @param the right parameter type * @return a lens that focuses on left values */ - public static Lens.Simple, Maybe> left() { + public static Lens.Simple, Maybe> _left() { return simpleLens(CoProduct2::projectA, (lOrR, maybeL) -> maybeL.>fmap(Either::left).orElse(lOrR)); } } diff --git a/src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java index 1d300f389..ef9aee18d 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/lenses/EitherLensTest.java @@ -17,7 +17,7 @@ public class EitherLensTest { @Test public void rightFocusesOnRightValues() { - Lens.Simple, Maybe> right = EitherLens.right(); + Lens.Simple, Maybe> right = EitherLens._right(); assertEquals(just(1), view(right, right(1))); assertEquals(nothing(), view(right, left("fail"))); @@ -29,7 +29,7 @@ public void rightFocusesOnRightValues() { @Test public void leftFocusesOnLeftValues() { - Lens.Simple, Maybe> left = EitherLens.left(); + Lens.Simple, Maybe> left = EitherLens._left(); assertEquals(just("fail"), view(left, left("fail"))); assertEquals(nothing(), view(left, right(1))); From 733b41d7fcc78841b5e7084f6e543b081c5f91ee Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 18:36:52 -0500 Subject: [PATCH 168/348] Cleaning up Optic javadoc --- src/main/java/com/jnape/palatable/lambda/optics/Optic.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java index be518ad7a..fb6ec0e59 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java @@ -10,8 +10,7 @@ * Precisely stated, for some {@link Profunctor} P and some {@link Functor} F, and for the * types S T A B, an * {@link Optic}<P, F, S, T, A, B> is a polymorphic function - * (P<A, F<B>> -> P<S, F<T>>) (existentially-quantified allowing for - * covariance). + * P<A, F<B>> -> P<S, F<T>>. * * @param

the {@link Profunctor} bound * @param the {@link Functor} bound From 1820d9e8631d749ab7fe2cacad1ed3b3874c381d Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 18:37:29 -0500 Subject: [PATCH 169/348] Cleaning up MapLens javadoc; SetLens#intersection removed (not lawful) --- .../lambda/optics/lenses/MapLens.java | 4 +- .../lambda/optics/lenses/SetLens.java | 40 ------------------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java index 7016716e7..729ca0b23 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/MapLens.java @@ -68,11 +68,11 @@ public static Lens.Simple, Map> asCopy() { * A lens that focuses on a value at a key in a map, as a {@link Maybe}, and produces a subtype M on * the way back out. * + * @param copyFn the copy function + * @param k the key to focus on * @param the map subtype * @param the key type * @param the value type - * @param k the key to focus on - * @param copyFn the copy function * @return a lens that focuses on the value at key, as a {@link Maybe} */ public static , K, V> Lens, M, Maybe, Maybe> valueAt( diff --git a/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java index 6b66649ed..75c7ab756 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/lenses/SetLens.java @@ -3,7 +3,6 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.optics.Lens; -import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -17,45 +16,6 @@ public final class SetLens { private SetLens() { } - /** - * A lens that focuses on whether a {@link Set} contains all values in as. Note that - * copyFn is used to avoid mutating the {@link Set} in question. - * - * @param copyFn the copy function - * @param as the values in question - * @param the value type - * @param the set to focus on - * @return a lens that focuses on the inclusion of a {@link Collection} of values in a given {@link Set} - */ - public static > Lens.Simple intersection( - Fn1 copyFn, - Set as) { - return simpleLens(setA -> { - SetA intersection = copyFn.apply(setA); - intersection.retainAll(as); - return intersection; - }, - (setA, setB) -> { - SetA copy = copyFn.apply(setA); - copy.retainAll(setB); - copy.retainAll(as); - return copy; - }); - } - - /** - * A lens that focuses on whether a {@link Set} contains some value a. Like - * {@link #intersection(Fn1, Set)} )} but with an implicit copy function that produces - * {@link HashSet}s. - * - * @param as the values in question - * @param the value type - * @return a lens that focuses on the inclusion of a {@link Collection} of values in a given {@link Set} - */ - public static Lens.Simple, Set> intersection(Set as) { - return intersection(HashSet::new, as); - } - /** * A lens that focuses on whether a {@link Set} contains some value a. Note that copyFn is * used to avoid mutating the {@link Set} in question. From 24a12ecb225477f7d9cdf19f624865acb0682400 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 18:37:52 -0500 Subject: [PATCH 170/348] Adding default prisms for Either, Maybe, Maps, and UUIDs --- .../lambda/optics/prisms/EitherPrism.java | 38 ++++++++ .../lambda/optics/prisms/MapPrism.java | 49 +++++++++++ .../lambda/optics/prisms/MaybePrism.java | 41 +++++++++ .../lambda/optics/prisms/UUIDPrism.java | 22 +++++ .../lambda/optics/prisms/EitherPrismTest.java | 26 ++++++ .../lambda/optics/prisms/MapPrismTest.java | 33 +++++++ .../lambda/optics/prisms/MaybePrismTest.java | 27 ++++++ .../lambda/optics/prisms/UUIDPrismTest.java | 20 +++++ .../testsupport/assertion/PrismAssert.java | 86 +++++++++++++++++++ 9 files changed, 342 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/prisms/EitherPrism.java create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/prisms/MapPrism.java create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/prisms/MaybePrism.java create mode 100644 src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java create mode 100644 src/test/java/com/jnape/palatable/lambda/optics/prisms/EitherPrismTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/optics/prisms/MapPrismTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/optics/prisms/MaybePrismTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrismTest.java create mode 100644 src/test/java/testsupport/assertion/PrismAssert.java diff --git a/src/main/java/com/jnape/palatable/lambda/optics/prisms/EitherPrism.java b/src/main/java/com/jnape/palatable/lambda/optics/prisms/EitherPrism.java new file mode 100644 index 000000000..462f30b0a --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/prisms/EitherPrism.java @@ -0,0 +1,38 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.optics.Prism; + +import static com.jnape.palatable.lambda.optics.Prism.simplePrism; + +/** + * {@link Prism Prisms} for {@link Either}. + */ +public final class EitherPrism { + + private EitherPrism() { + } + + /** + * A {@link Prism} that focuses on the {@link Either#left(Object) left} value of an {@link Either}. + * + * @param the left type + * @param the right type + * @return the {@link Prism} + */ + public static Prism.Simple, L> _left() { + return simplePrism(CoProduct2::projectA, Either::left); + } + + /** + * A {@link Prism} that focuses on the {@link Either#right(Object) right} value of an {@link Either}. + * + * @param the left type + * @param the right type + * @return the {@link Prism} + */ + public static Prism.Simple, R> _right() { + return simplePrism(CoProduct2::projectB, Either::right); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/prisms/MapPrism.java b/src/main/java/com/jnape/palatable/lambda/optics/prisms/MapPrism.java new file mode 100644 index 000000000..2d1ee7930 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/prisms/MapPrism.java @@ -0,0 +1,49 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.optics.Prism; + +import java.util.HashMap; +import java.util.Map; + +import static com.jnape.palatable.lambda.adt.Maybe.maybe; +import static com.jnape.palatable.lambda.optics.Prism.Simple.adapt; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static java.util.Collections.singletonMap; + +/** + * {@link Prism Prisms} for {@link Map Maps}. + */ +public final class MapPrism { + private MapPrism() { + } + + /** + * A {@link Prism} that focuses on the value at a key in a {@link Map}, and produces an instance of M + * on the way back out. + * + * @param copyFn the copy function + * @param k the key to focus on + * @param the {@link Map} subtype + * @param the key type + * @param the value type + * @return the {@link Prism} + */ + public static , K, V> Prism, M, V, V> valueAt(Fn1, M> copyFn, K k) { + return prism(m -> maybe(m.get(k)).toEither(copyFn.thunk(m)), + v -> copyFn.apply(singletonMap(k, v))); + } + + /** + * A {@link Prism} that focuses on the value at a key in a {@link Map} making no guarantees about the {@link Map} + * interface. + * + * @param k the key to focus on + * @param the key type + * @param the value type + * @return the {@link Prism} + */ + public static Prism.Simple, V> valueAt(K k) { + return adapt(valueAt(HashMap::new, k)); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/prisms/MaybePrism.java b/src/main/java/com/jnape/palatable/lambda/optics/prisms/MaybePrism.java new file mode 100644 index 000000000..eaf5ed0f1 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/prisms/MaybePrism.java @@ -0,0 +1,41 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.optics.Prism; + +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.optics.Prism.prism; +import static com.jnape.palatable.lambda.optics.Prism.simplePrism; + +/** + * {@link Prism Prisms} for {@link Maybe}. + */ +public final class MaybePrism { + + private MaybePrism() { + } + + /** + * A {@link Prism} that focuses on present values in a {@link Maybe}. + * + * @param {@link Maybe} the input value + * @param {@link Maybe} the output value + * @return the {@link Prism} + */ + public static Prism, Maybe, A, B> _just() { + return prism(maybeA -> maybeA.toEither(Maybe::nothing), Maybe::just); + } + + /** + * A {@link Prism} that focuses on absent values in a {@link Maybe}, for symmetry. + * + * @param {@link Maybe} the input and output value + * @return the {@link Prism} + */ + public static Prism.Simple, Unit> _nothing() { + return simplePrism(CoProduct2::projectA, constantly(nothing())); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java b/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java new file mode 100644 index 000000000..c9a70080e --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java @@ -0,0 +1,22 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import com.jnape.palatable.lambda.optics.Prism; + +import java.util.UUID; + +/** + * {@link Prism Prisms} for {@link UUID}. + */ +public final class UUIDPrism { + private UUIDPrism() { + } + + /** + * A {@link Prism} that focuses on a {@link String} as a {@link UUID}. + * + * @return the {@link Prism} + */ + public static Prism.Simple uuid() { + return Prism.fromPartial(UUID::fromString, UUID::toString); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/optics/prisms/EitherPrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/prisms/EitherPrismTest.java new file mode 100644 index 000000000..cb1e09357 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/prisms/EitherPrismTest.java @@ -0,0 +1,26 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static testsupport.assertion.PrismAssert.assertPrismLawfulness; + +public class EitherPrismTest { + + @Test + public void _right() { + assertPrismLawfulness(EitherPrism._right(), + asList(left("foo"), right(1)), + singleton(1)); + } + + @Test + public void _left() { + assertPrismLawfulness(EitherPrism._left(), + asList(left("foo"), right(1)), + singleton("foo")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/prisms/MapPrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/prisms/MapPrismTest.java new file mode 100644 index 000000000..7ba1dd09f --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/prisms/MapPrismTest.java @@ -0,0 +1,33 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.LinkedHashMap; + +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonMap; +import static testsupport.assertion.PrismAssert.assertPrismLawfulness; + +public class MapPrismTest { + + @Test + public void valueAtWithConstructor() { + assertPrismLawfulness(MapPrism.valueAt(LinkedHashMap::new, "foo"), + asList(new LinkedHashMap<>(), + new LinkedHashMap<>(singletonMap("foo", 1)), + new LinkedHashMap<>(singletonMap("bar", 2))), + singleton(1)); + } + + @Test + public void valueAtWithoutConstructor() { + assertPrismLawfulness(MapPrism.valueAt("foo"), + asList(new HashMap<>(), + new HashMap<>(singletonMap("foo", 1)), + new HashMap<>(singletonMap("bar", 2))), + singleton(1)); + } + +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/prisms/MaybePrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/prisms/MaybePrismTest.java new file mode 100644 index 000000000..5d772a6c5 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/prisms/MaybePrismTest.java @@ -0,0 +1,27 @@ +package com.jnape.palatable.lambda.optics.prisms; + +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.Unit.UNIT; +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static testsupport.assertion.PrismAssert.assertPrismLawfulness; + +public class MaybePrismTest { + + @Test + public void _just() { + assertPrismLawfulness(MaybePrism._just(), + asList(just(1), nothing()), + singleton(1)); + } + + @Test + public void _nothing() { + assertPrismLawfulness(MaybePrism._nothing(), + asList(just(1), nothing()), + singleton(UNIT)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrismTest.java new file mode 100644 index 000000000..24bf6421a --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrismTest.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.optics.prisms; + +import org.junit.Test; + +import java.util.UUID; + +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static testsupport.assertion.PrismAssert.assertPrismLawfulness; + +public class UUIDPrismTest { + + @Test + public void uuid() { + UUID uuid = UUID.randomUUID(); + assertPrismLawfulness(UUIDPrism.uuid(), + asList("", "123", uuid.toString()), + singleton(uuid)); + } +} \ No newline at end of file diff --git a/src/test/java/testsupport/assertion/PrismAssert.java b/src/test/java/testsupport/assertion/PrismAssert.java new file mode 100644 index 000000000..9794678de --- /dev/null +++ b/src/test/java/testsupport/assertion/PrismAssert.java @@ -0,0 +1,86 @@ +package testsupport.assertion; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.builtin.fn2.Map; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monoid.builtin.Present; +import com.jnape.palatable.lambda.optics.Prism; + +import java.util.Objects; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.builtin.fn1.CatMaybes.catMaybes; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn2.CartesianProduct.cartesianProduct; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; +import static com.jnape.palatable.lambda.optics.functions.Matching.matching; +import static com.jnape.palatable.lambda.optics.functions.Pre.pre; +import static com.jnape.palatable.lambda.optics.functions.Re.re; +import static com.jnape.palatable.lambda.optics.functions.View.view; +import static java.lang.String.format; +import static java.lang.String.join; +import static java.util.Arrays.asList; + +public final class PrismAssert { + + public static void assertPrismLawfulness(Prism prism, + Iterable ss, + Iterable bs) { + Iterable> cases = cartesianProduct(ss, bs); + Present.present((x, y) -> join("\n\n", x, y)) + .reduceLeft(asList(falsify("The result of a review can always be successfully previewed:", + (s, b) -> view(pre(prism), view(re(prism), b)), (s, b) -> just(b), cases), + falsify("If I can preview a value from an input, I can review the input to the value", + (s, b) -> new PrismResult<>(view(pre(prism), s).fmap(constantly(s))), + (s, b) -> new PrismResult<>(just(view(re(prism), b))), cases), + falsify("A non-match result can always be converted back to an input", + (s, b) -> new PrismResult<>(matching(prism, s).projectA().fmap(matching(prism))), + (s, b) -> new PrismResult<>(just(left(s))), cases))) + .peek(failures -> IO.throwing(new AssertionError("Lens law failures\n\n" + failures))); + } + + private static Maybe falsify(String label, Fn2 l, Fn2 r, + Iterable> cases) { + return Map., Maybe>map(into((s, b) -> { + X x = l.apply(s, b); + X y = r.apply(s, b); + return Objects.equals(x, y) ? nothing() : just(format("S <%s>, B <%s> (%s != %s)", s, b, x, y)); + })) + .fmap(catMaybes()) + .fmap(reduceLeft((x, y) -> x + "\n\t - " + y)) + .fmap(maybeFailures -> maybeFailures.fmap(failures -> "\"" + label + "\" failed for the following cases:\n\n\t - " + failures)) + .apply(cases); + } + + private static final class PrismResult { + private final Maybe maybeS; + + private PrismResult(Maybe maybeS) { + this.maybeS = maybeS; + } + + @Override + public boolean equals(Object other) { + if (other instanceof PrismResult) { + return maybeS.zip(((PrismResult) other).maybeS.fmap(fn2(Objects::equals))).orElse(true); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(maybeS); + } + + @Override + public String toString() { + return maybeS.toString(); + } + } +} From 3259969772c5751de5f305b7a19649677e8c6892 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 18:41:54 -0500 Subject: [PATCH 171/348] Intersection is a Semigroup --- .../builtin/fn2 => semigroup/builtin}/Intersection.java | 6 +++--- .../com/jnape/palatable/lambda/traversable/Traversable.java | 3 +++ .../builtin/fn2 => semigroup/builtin}/IntersectionTest.java | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) rename src/main/java/com/jnape/palatable/lambda/{functions/builtin/fn2 => semigroup/builtin}/Intersection.java (88%) rename src/test/java/com/jnape/palatable/lambda/{functions/builtin/fn2 => semigroup/builtin}/IntersectionTest.java (92%) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java similarity index 88% rename from src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java rename to src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java index e7965d9ae..cf33e9b3a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Intersection.java @@ -1,8 +1,8 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; +package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn1.Distinct; +import com.jnape.palatable.lambda.semigroup.Semigroup; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; @@ -16,7 +16,7 @@ * * @param the {@link Iterable} element type */ -public final class Intersection implements Fn2, Iterable, Iterable> { +public final class Intersection implements Semigroup> { private static final Intersection INSTANCE = new Intersection<>(); diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java index d9f24621c..54caa1317 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/Traversable.java @@ -47,6 +47,9 @@ public interface Traversable> extends Functor> AppTrav traverse( Fn1> fn, Fn1 pure); + /** + * {@inheritDoc} + */ @Override default Traversable fmap(Fn1 fn) { return traverse(a -> new Identity(fn.apply(a)), Identity::new).runIdentity(); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersectionTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java similarity index 92% rename from src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersectionTest.java rename to src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java index 13c16ace3..0ecd33c71 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersectionTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/IntersectionTest.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; +package com.jnape.palatable.lambda.semigroup.builtin; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -10,7 +10,7 @@ import testsupport.traits.InfiniteIterableSupport; import testsupport.traits.Laziness; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Intersection.intersection; +import static com.jnape.palatable.lambda.semigroup.builtin.Intersection.intersection; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; From 9ae0f1451b93e68aa9e34de584893358f7f33594 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 18:47:09 -0500 Subject: [PATCH 172/348] Adding the Trivial Unit monoid for when composition demands it --- .../lambda/monoid/builtin/Trivial.java | 41 +++++++++++++++++++ .../lambda/monoid/builtin/TrivialTest.java | 16 ++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monoid/builtin/Trivial.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monoid/builtin/TrivialTest.java diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Trivial.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Trivial.java new file mode 100644 index 000000000..bf77b65f1 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Trivial.java @@ -0,0 +1,41 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Constantly; +import com.jnape.palatable.lambda.monoid.Monoid; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; + +/** + * The trivial {@link Unit} {@link Monoid} formed under {@link Constantly constantly}. + */ +public final class Trivial implements Monoid { + + private static final Trivial INSTANCE = new Trivial(); + + private Trivial() { + } + + @Override + public Unit identity() { + return UNIT; + } + + @Override + public Unit checkedApply(Unit x, Unit y) throws Throwable { + return y; + } + + public static Trivial trivial() { + return INSTANCE; + } + + public static Fn1 trivial(Unit x) { + return trivial().apply(x); + } + + public static Unit trivial(Unit x, Unit y) { + return trivial(x).apply(y); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/TrivialTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/TrivialTest.java new file mode 100644 index 000000000..da28c59f6 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/TrivialTest.java @@ -0,0 +1,16 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.monoid.builtin.Trivial.trivial; +import static org.junit.Assert.assertEquals; + +public class TrivialTest { + + @Test + public void triviality() { + assertEquals(UNIT, trivial().identity()); + assertEquals(UNIT, trivial().apply(UNIT, UNIT)); + } +} \ No newline at end of file From a14042c08ca7b15ac1544d05bf369660074c789f Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 18:52:21 -0500 Subject: [PATCH 173/348] Fixing javadocs --- src/main/java/com/jnape/palatable/lambda/adt/Try.java | 1 + src/main/java/com/jnape/palatable/lambda/functions/Effect.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index 40a678339..bdc2ec040 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -122,6 +122,7 @@ public final A orThrow() throws T { * If this is a success value, return it. Otherwise, transform the captured failure with fn and throw * the result. * + * @param fn the {@link Throwable} transformation * @param the type of the thrown {@link Throwable} * @return possibly the success value * @throws T the transformation output diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 077935f49..648c42eab 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -95,6 +95,7 @@ static Effect fromConsumer(Consumer consumer) { * Create an {@link Effect} from a {@link SideEffect}; * * @param sideEffect the {@link SideEffect} + * @param any desired input type * @return the {@link Effect} */ static Effect effect(SideEffect sideEffect) { @@ -104,6 +105,7 @@ static Effect effect(SideEffect sideEffect) { /** * Create an {@link Effect} that accepts an input and does nothing; * + * @param any desired input type * @return the noop {@link Effect} */ @SuppressWarnings("unused") From bc366576d65c81827a9b17a0cbc187a3b02abc7a Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 18:59:40 -0500 Subject: [PATCH 174/348] CompletableFuture#thenCompose isn't stack-safe, so c-switch zips for now --- src/main/java/com/jnape/palatable/lambda/io/IO.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index a42181bd2..c86fcbc59 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -312,10 +312,10 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { @SuppressWarnings("unchecked") CompletableFuture future = (CompletableFuture) deforest(new LinkedList<>()) .into((source, compositions) -> foldLeft( - (io, composition) -> composition + (ioFuture, composition) -> composition .match(zip -> zip.unsafePerformAsyncIO(executor) - .thenCompose(f -> io.thenApply(f.toFunction())), - flatMap -> io.thenComposeAsync(obj -> flatMap.apply(obj) + .thenComposeAsync(f -> ioFuture.thenApply(f.toFunction()), executor), + flatMap -> ioFuture.thenComposeAsync(obj -> flatMap.apply(obj) .unsafePerformAsyncIO(executor), executor)), source.unsafePerformAsyncIO(executor), compositions)); From 03eca049ece575991f43ba12d6befc17f19b2447 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 19 May 2019 19:19:09 -0500 Subject: [PATCH 175/348] Bumping version to 4.0.0-SNAPSHOT; removing apache-commons test dep --- pom.xml | 12 +++--------- .../java/testsupport/matchers/IterableMatcher.java | 4 ++-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 00b717374..a913949f3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -9,7 +10,7 @@ lambda - 3.3.1-SNAPSHOT + 4.0.0-SNAPSHOT jar Lambda @@ -53,7 +54,6 @@ - 3.1 1.2 3.3 1.3 @@ -81,12 +81,6 @@ ${traitor.version} test - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - test - diff --git a/src/test/java/testsupport/matchers/IterableMatcher.java b/src/test/java/testsupport/matchers/IterableMatcher.java index 5478e46e3..f5f196aba 100644 --- a/src/test/java/testsupport/matchers/IterableMatcher.java +++ b/src/test/java/testsupport/matchers/IterableMatcher.java @@ -5,9 +5,9 @@ import java.util.ArrayList; import java.util.Iterator; +import java.util.Objects; import static java.util.Arrays.asList; -import static org.apache.commons.lang3.builder.EqualsBuilder.reflectionEquals; public class IterableMatcher extends BaseMatcher> { @@ -48,7 +48,7 @@ private boolean iterablesIterateSameElementsInOrder(Iterable expected, Iterab if (nextExpected instanceof Iterable && nextActual instanceof Iterable) { if (!iterablesIterateSameElementsInOrder((Iterable) nextExpected, (Iterable) nextActual)) return false; - } else if (!reflectionEquals(nextExpected, nextActual)) + } else if (!Objects.equals(nextExpected, nextActual)) return false; } From bde58127064cb8c2b96c74304fd72ab6bb736e5b Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 20 May 2019 23:36:49 -0500 Subject: [PATCH 176/348] Prisms are Profunctors --- .../jnape/palatable/lambda/optics/Prism.java | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java index f90635c63..d89ad3bfb 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -53,7 +53,10 @@ * @param the input that guarantees its output */ @FunctionalInterface -public interface Prism extends ProtoOptic, S, T, A, B>, Monad> { +public interface Prism extends + ProtoOptic, S, T, A, B>, + Monad>, + Profunctor> { /** * Recover the two mappings encapsulated by this {@link Prism} by sending it through a {@link Market}. @@ -140,6 +143,39 @@ default Prism discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ + @Override + default Prism diMap(Fn1 lFn, + Fn1 rFn) { + return unPrism().into((bt, seta) -> prism(seta.diMap(lFn, tOrA -> tOrA.biMapL(rFn)), bt.fmap(rFn))); + } + + /** + * {@inheritDoc} + */ + @Override + default Prism diMapL(Fn1 fn) { + return (Prism) Profunctor.super.diMapL(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Prism diMapR(Fn1 fn) { + return (Prism) Profunctor.super.diMapR(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Prism contraMap(Fn1 fn) { + return (Prism) Profunctor.super.contraMap(fn); + } + /** * Static factory method for creating a {@link Prism} given a mapping from * S -> {@link Either}<T, A> and a mapping from B -> T. From 2feae8164ec31f784af55121e5ff15beb18af1b2 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 20 May 2019 23:45:32 -0500 Subject: [PATCH 177/348] [maven-release-plugin] prepare release lambda-4.0.0 --- pom.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index a913949f3..ddf6ce35a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -10,7 +9,7 @@ lambda - 4.0.0-SNAPSHOT + 4.0.0 jar Lambda From dc7a459128261ca350ed6daff01c885af6655766 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 20 May 2019 23:45:39 -0500 Subject: [PATCH 178/348] [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 ddf6ce35a..31902087d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 4.0.0 + 4.0.1-SNAPSHOT jar Lambda From d02df8a48541a89dcc3b73b89ea3ff90837d5dc1 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 24 May 2019 01:47:13 -0500 Subject: [PATCH 179/348] Updating CHANGELOG and README --- CHANGELOG.md | 8 ++++++-- README.md | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc0afb897..6c74ca50b 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 changes yet + +## [4.0.0] - 2019-05-20 ### Changed - ***Breaking Change***: `IO` is now sealed and moved to its own package. Most previous constructions using the static factory methods should continue to work (by simply targeting `Supplier` now instead of an @@ -475,8 +478,9 @@ 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.3.0...HEAD -[3.3.0]: https://github.com/palatable/lambda/compare/lambda-3.2.0...3.3.0 +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-4.0.0...HEAD +[4.0.0]: https://github.com/palatable/lambda/compare/lambda-3.3.0...lambda-4.0.0 +[3.3.0]: https://github.com/palatable/lambda/compare/lambda-3.2.0...lambda-3.3.0 [3.2.0]: https://github.com/palatable/lambda/compare/lambda-3.1.0...lambda-3.2.0 [3.1.0]: https://github.com/palatable/lambda/compare/lambda-3.0.3...lambda-3.1.0 [3.0.3]: https://github.com/palatable/lambda/compare/lambda-3.0.2...lambda-3.0.3 diff --git a/README.md b/README.md index 476f89ebc..18584232d 100644 --- a/README.md +++ b/README.md @@ -58,14 +58,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 3.3.0 + 4.0.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '3.3.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '4.0.0' ``` Examples From 585c164c979edc552007580157c24873a4f6263d Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 25 May 2019 14:50:02 -0500 Subject: [PATCH 180/348] Adding javadoc --- .../com/jnape/palatable/lambda/optics/Optic.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java index fb6ec0e59..d0dc2d625 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Optic.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Optic.java @@ -22,6 +22,18 @@ @FunctionalInterface public interface Optic

, F extends Functor, S, T, A, B> { + /** + * The polymorphic arrow between profunctors in this optic interface. + * + * @param pafb the input + * @param the profunctor type constraint witnessed by the application of this optic + * @param the functor type constraint witnessed by the application of this optic + * @param the covariant parameter type of the input profunctor + * @param the covariant parameter type of the output profunctor + * @param the full input type + * @param the full output type + * @return the output profunctor + */ , CoF extends Functor, FB extends Functor, From 9e238bf12bcab1f9b5d5ca6b624898298f952875 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 25 May 2019 14:52:01 -0500 Subject: [PATCH 181/348] EitherT exposes the nested Either's bifunctor properties --- .../monad/transformer/builtin/EitherT.java | 30 ++++++++++++++++++- .../transformer/builtin/EitherTTest.java | 3 +- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java index d8a139f39..7b1cb0deb 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -20,7 +21,9 @@ * @param the left type * @param the right type */ -public final class EitherT, L, R> implements MonadT, R> { +public final class EitherT, L, R> implements + Bifunctor>, + MonadT, R> { private final Monad, M> melr; @@ -100,6 +103,31 @@ public EitherT discardR(Applicative, ?>> return MonadT.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public EitherT biMap(Fn1 lFn, + Fn1 rFn) { + return eitherT(melr.fmap(e -> e.biMap(lFn, rFn))); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT biMapL(Fn1 fn) { + return (EitherT) Bifunctor.super.biMapL(fn); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT biMapR(Fn1 fn) { + return (EitherT) Bifunctor.super.biMapR(fn); + } + @Override public boolean equals(Object other) { return other instanceof EitherT && Objects.equals(melr, ((EitherT) other).melr); diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java index b5d717b69..4b7a7a889 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -22,7 +23,7 @@ @RunWith(Traits.class) public class EitherTTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class}) public Subjects, String, Integer>> testSubject() { return subjects(eitherT(new Identity<>(left("foo"))), eitherT(new Identity<>(right(1)))); } From 65b0e309a92b110704cf6eeca5a069ff1126a89b Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 25 May 2019 15:22:08 -0500 Subject: [PATCH 182/348] Composing a prism with another prism yields a prism. Defaults for optics --- .../jnape/palatable/lambda/optics/Prism.java | 84 +++++++++++++++- .../palatable/lambda/optics/ProtoOptic.java | 97 ++++++++++++++++++- .../lambda/optics/prisms/UUIDPrism.java | 5 +- .../palatable/lambda/optics/PrismTest.java | 28 ++++++ 4 files changed, 208 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java index d89ad3bfb..c15f2185f 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -84,6 +84,54 @@ public interface Prism extends return optic.apply(pafb); } + /** + * {@inheritDoc} + */ + @Override + default Prism andThen(ProtoOptic, A, B, Z, C> f) { + return prism(ProtoOptic.super.andThen(f)); + } + + /** + * {@inheritDoc} + */ + @Override + default Prism compose(ProtoOptic, R, U, S, T> g) { + return prism(ProtoOptic.super.compose(g)); + } + + /** + * {@inheritDoc} + */ + @Override + default Prism mapS(Fn1 fn) { + return prism(ProtoOptic.super.mapS(fn)); + } + + /** + * {@inheritDoc} + */ + @Override + default Prism mapT(Fn1 fn) { + return prism(ProtoOptic.super.mapT(fn)); + } + + /** + * {@inheritDoc} + */ + @Override + default Prism mapA(Fn1 fn) { + return prism(ProtoOptic.super.mapA(fn)); + } + + /** + * {@inheritDoc} + */ + @Override + default Prism mapB(Fn1 fn) { + return prism(ProtoOptic.super.mapB(fn)); + } + /** * {@inheritDoc} */ @@ -264,10 +312,21 @@ static Prism.Simple simplePrism(Fn1> return Prism.prism(s -> sMaybeA.apply(s).toEither(() -> s), as)::toOptic; } - - static Prism.Simple fromPartial(Fn1 partialSa, - Fn1 as) { - return adapt(prism(partialSa.diMap(downcast(), upcast()).choose(), as)); + /** + * Static factory method for creating a {@link Prism} from a partial function S -> A and a total + * function B -> S. + * + * @param partialSa the partial direction + * @param bs the reverse total direction + * @param the input that might fail to map to its output and the guaranteed output from the other + * direction + * @param the output that might fail to be produced + * @param the input that guarantees its output in the other direction + * @return the {@link Prism} + */ + static Prism fromPartial(Fn1 partialSa, + Fn1 bs) { + return prism(partialSa.diMap(downcast(), upcast()).choose(), bs); } /** @@ -322,5 +381,22 @@ static Prism.Simple adapt( Optic, ? super Functor, S, S, A, A> optic) { return adapt(prism(optic)); } + + /** + * Static factory method for creating a {@link Prism.Simple simple Prism} from a partial function + * S -> A and a total function A -> T. + * + * @param partialSa the partial direction + * @param as the reverse total direction + * @param the input that might fail to map to its output and the guaranteed output from the other + * direction + * @param the output that might fail to be produced and the input that guarantees its output in the + * other direction + * @return the {@link Prism.Simple simple Prism} + */ + static Prism.Simple fromPartial(Fn1 partialSa, + Fn1 as) { + return adapt(Prism.fromPartial(partialSa, as)); + } } } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java b/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java index 57fc5ffbc..5904ea4be 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/ProtoOptic.java @@ -1,14 +1,18 @@ package com.jnape.palatable.lambda.optics; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.functor.builtin.Identity; +import static com.jnape.palatable.lambda.optics.Optic.reframe; + /** * A generic supertype representation for a profunctor {@link Optic} that requires a {@link Pure} implementation to - * derive its {@link Functor} constraint and graduate to a full-fledge {@link Optic}. + * derive its {@link Functor} constraint and graduate to a full-fledge {@link Optic}, equipped with a default + * {@link Optic} instance for the profunctor constraint and {@link Identity}. * * @param

the {@link Profunctor} bound * @param the left side of the output profunctor @@ -30,6 +34,9 @@ public interface ProtoOptic

, S, T, A, B> */ > Optic toOptic(Pure pure); + /** + * {@inheritDoc} + */ @Override default , CoF extends Functor>, FB extends Functor, FT extends Functor, @@ -37,4 +44,92 @@ public interface ProtoOptic

, S, T, A, B> PSFT extends Profunctor> PSFT apply(PAFB pafb) { return toOptic(Pure.>pure(Identity::new)).apply(pafb); } + + /** + * Left-to-right composition of proto-optics. Requires compatibility between S and T. + * + * @param f the other proto-optic + * @param the new left side of the input profunctor + * @param the new right side's functor embedding of the input profunctor + * @return the composed proto-optic + */ + default ProtoOptic andThen(ProtoOptic f) { + return new ProtoOptic() { + @Override + public > Optic toOptic(Pure pure) { + Optic optic = f.toOptic(pure); + return ProtoOptic.this.toOptic(pure).andThen(reframe(optic)); + } + }; + } + + /** + * Right-to-Left composition of proto-optics. Requires compatibility between A and B. + * + * @param g the other proto-optic + * @param the new left side of the output profunctor + * @param the new right side's functor embedding of the output profunctor + * @return the composed proto-optic + */ + default ProtoOptic compose(ProtoOptic g) { + return new ProtoOptic() { + @Override + public > Optic toOptic(Pure pure) { + Optic optic = g.toOptic(pure); + return ProtoOptic.this.toOptic(pure).compose(reframe(optic)); + } + }; + } + + /** + * {@inheritDoc} + */ + @Override + default ProtoOptic mapS(Fn1 fn) { + return new ProtoOptic() { + @Override + public > Optic toOptic(Pure pure) { + return ProtoOptic.this.toOptic(pure).mapS(fn); + } + }; + } + + /** + * {@inheritDoc} + */ + @Override + default ProtoOptic mapT(Fn1 fn) { + return new ProtoOptic() { + @Override + public > Optic toOptic(Pure pure) { + return ProtoOptic.this.toOptic(pure).mapT(fn); + } + }; + } + + /** + * {@inheritDoc} + */ + @Override + default ProtoOptic mapA(Fn1 fn) { + return new ProtoOptic() { + @Override + public > Optic toOptic(Pure pure) { + return ProtoOptic.this.toOptic(pure).mapA(fn); + } + }; + } + + /** + * {@inheritDoc} + */ + @Override + default ProtoOptic mapB(Fn1 fn) { + return new ProtoOptic() { + @Override + public > Optic toOptic(Pure pure) { + return ProtoOptic.this.toOptic(pure).mapB(fn); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java b/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java index c9a70080e..1a030b654 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/prisms/UUIDPrism.java @@ -4,10 +4,13 @@ import java.util.UUID; +import static com.jnape.palatable.lambda.optics.Prism.Simple.fromPartial; + /** * {@link Prism Prisms} for {@link UUID}. */ public final class UUIDPrism { + private UUIDPrism() { } @@ -17,6 +20,6 @@ private UUIDPrism() { * @return the {@link Prism} */ public static Prism.Simple uuid() { - return Prism.fromPartial(UUID::fromString, UUID::toString); + return fromPartial(UUID::fromString, UUID::toString); } } diff --git a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java index b2080bb0b..1eac70adf 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java @@ -15,13 +15,17 @@ import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; import static com.jnape.palatable.lambda.optics.Prism.prism; import static com.jnape.palatable.lambda.optics.Prism.simplePrism; import static com.jnape.palatable.lambda.optics.functions.Matching.matching; import static com.jnape.palatable.lambda.optics.functions.Pre.pre; import static com.jnape.palatable.lambda.optics.functions.Re.re; import static com.jnape.palatable.lambda.optics.functions.View.view; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; +import static testsupport.assertion.PrismAssert.assertPrismLawfulness; @RunWith(Traits.class) public class PrismTest { @@ -60,4 +64,28 @@ public void unPrismExtractsMappings() { assertEquals(right(123), sis.apply("123")); assertEquals(left("foo"), sis.apply("foo")); } + + @Test + public void andThen() { + Prism.Simple stringFloat = Prism.Simple.fromPartial(Float::parseFloat, Object::toString); + Prism.Simple floatInt = simplePrism(f -> just(f.intValue()).filter(i -> eq(i.floatValue(), f)), + Integer::floatValue); + Prism composed = stringFloat.andThen(floatInt); + + assertPrismLawfulness(composed, singletonList("1.2"), singletonList(1)); + assertPrismLawfulness(composed, singletonList("1.0"), singletonList(1)); + assertPrismLawfulness(composed, singletonList("foo"), emptyList()); + } + + @Test + public void composed() { + Prism.Simple stringFloat = Prism.Simple.fromPartial(Float::parseFloat, Object::toString); + Prism.Simple floatInt = simplePrism(f -> just(f.intValue()).filter(i -> eq(i.floatValue(), f)), + Integer::floatValue); + Prism composed = floatInt.compose(stringFloat); + + assertPrismLawfulness(composed, singletonList("1.2"), singletonList(1)); + assertPrismLawfulness(composed, singletonList("1.0"), singletonList(1)); + assertPrismLawfulness(composed, singletonList("foo"), emptyList()); + } } \ No newline at end of file From d3c6d297436f7271d0d0482c6c80623ea04025a0 Mon Sep 17 00:00:00 2001 From: Kevin Schuetz Date: Mon, 3 Jun 2019 18:55:51 -0500 Subject: [PATCH 183/348] Improve docs for Intersperse (#54) --- .../palatable/lambda/functions/builtin/fn2/Intersperse.java | 4 ++-- .../lambda/functions/builtin/fn2/IntersperseTest.java | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java index 4ff11cdec..a4a0b2e51 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersperse.java @@ -7,8 +7,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.PrependAll.prependAll; /** - * Lazily inject the provided separator value between each value in the supplied Iterable. An empty - * Iterable is left untouched. + * Lazily inject the provided separator value between each value in the supplied Iterable. An + * Iterable with fewer than two elements is left untouched. * * @param the Iterable parameter type * @see PrependAll diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersperseTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersperseTest.java index c87acc89e..8a6308326 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersperseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IntersperseTest.java @@ -30,6 +30,11 @@ public void interspersesBetweenElementsInIterable() { assertThat(intersperse(0, asList(1, 2, 3)), iterates(1, 0, 2, 0, 3)); } + @Test + public void doesNotIntersperseSingletonIterable() { + assertThat(intersperse(0, asList(1)), iterates(1)); + } + @Test public void doesNotIntersperseEmptyIterable() { assertThat(intersperse(0, emptyList()), isEmpty()); From 8c92260f5962af20904df3113953af520cfb7b6f Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 29 May 2019 01:34:21 -0500 Subject: [PATCH 184/348] Updating CHANGELOG --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c74ca50b..4e2c2dac6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,10 @@ 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 changes yet +### Added +- `Optic#andThen`, `Optic#compose`, and other defaults added +- `Prism#andThen`, `Prism#compose` begets another `Prism` +- `Prism#fromPartial` public interfaces ## [4.0.0] - 2019-05-20 ### Changed From d7fac75845df25e4c8dad1466b8f8f41bca2a865 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 1 Jun 2019 09:59:11 -0500 Subject: [PATCH 185/348] Adding ReaderT --- CHANGELOG.md | 1 + .../monad/transformer/builtin/ReaderT.java | 173 ++++++++++++++++++ .../transformer/builtin/ReaderTTest.java | 45 +++++ 3 files changed, 219 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e2c2dac6..6396ed612 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Optic#andThen`, `Optic#compose`, and other defaults added - `Prism#andThen`, `Prism#compose` begets another `Prism` - `Prism#fromPartial` public interfaces +- `ReaderT`, the transformer for the reader monad ## [4.0.0] - 2019-05-20 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java new file mode 100644 index 000000000..e38ece76d --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -0,0 +1,173 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Cartesian; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; + +/** + * A {@link MonadT monad transformer} for any {@link Fn1 function} from some type R to some + * {@link Monad monadic} embedding {@link Monad}<A, M>. + * + * @param the input type + * @param the returned {@link Monad} + * @param the embedded output type + */ +public interface ReaderT, A> extends + MonadT, M, A>, + Cartesian> { + + /** + * Run the computation represented by this {@link ReaderT}. + * + * @param r the input + * @return the {¬@link Monad monadic} embedding {@link Monad}<A, M> + */ + Monad runReaderT(R r); + + /** + * Map the current {@link Monad monadic} embedding to a new one in a potentially different {@link Monad}. + * + * @param fn the mapping function + * @param the inference target of the current {@link Monad monadic} embedding + * @param the new {@link Monad} to embed the result in + * @param the new embedded result + * @return the mapped {@link ReaderT} + */ + default , N extends Monad, B> ReaderT mapReaderT( + Fn1> fn) { + return readerT(r -> fn.apply(runReaderT(r).coerce())); + } + + /** + * {@inheritDoc} + */ + @Override + default , FGA extends Monad>> FGA run() { + return Fn1.fn1(r -> runReaderT(r).coerce()).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT flatMap(Fn1, M, ?>>> f) { + return readerT(r -> runReaderT(r).flatMap(a -> f.apply(a).>coerce().runReaderT(r))); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT pure(B b) { + return readerT(r -> runReaderT(r).pure(b)); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT fmap(Fn1 fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT zip(Applicative, MonadT, M, ?>> appFn) { + return readerT(r -> runReaderT(r).zip(appFn.>>coerce().runReaderT(r))); + } + + /** + * {@inheritDoc} + */ + @Override + default Lazy> lazyZip( + Lazy, MonadT, M, ?>>> lazyAppFn) { + return lazyAppFn.fmap(this::zip); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT discardL(Applicative, M, ?>> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT discardR(Applicative, M, ?>> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT diMap(Fn1 lFn, Fn1 rFn) { + return readerT(q -> runReaderT(lFn.apply(q)).fmap(rFn)); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT diMapL(Fn1 fn) { + return (ReaderT) Cartesian.super.diMapL(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT diMapR(Fn1 fn) { + return (ReaderT) Cartesian.super.diMapR(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT contraMap(Fn1 fn) { + return (ReaderT) Cartesian.super.contraMap(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT, M, Tuple2> cartesian() { + return readerT(into((c, r) -> runReaderT(r).fmap(tupler(c)))); + } + + /** + * {@inheritDoc} + */ + @Override + default ReaderT> carry() { + return (ReaderT>) Cartesian.super.carry(); + } + + /** + * Lift a {@link Fn1 function} (R -> {@link Monad}<A, M>) into a {@link ReaderT} instance. + * + * @param fn the function + * @param the input type + * @param the returned {@link Monad} + * @param the embedded output type + * @return the {@link ReaderT} + */ + static , A> ReaderT readerT(Fn1> fn) { + return fn::apply; + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java new file mode 100644 index 000000000..aedd4a47a --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java @@ -0,0 +1,45 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.MonadT; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.EquatableM; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.monad.transformer.builtin.ReaderT.readerT; +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class ReaderTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + public EquatableM, Identity, ?>, Integer> testSubject() { + return new EquatableM<>(readerT(Identity::new), + readerT -> ((Fn1>>) readerT.run()).apply(1)); + } + + @Test + public void profunctor() { + assertEquals(new Identity<>(4), + ReaderT., Integer>readerT(Identity::new) + .diMap(String::length, x -> x + 1) + .runReaderT("123")); + } + + @Test + public void mapReaderT() { + assertEquals(just(3), + ReaderT., String>readerT(Identity::new) + ., Maybe, Integer>mapReaderT(id -> just(id.runIdentity().length())) + .runReaderT("foo")); + } +} \ No newline at end of file From 4a56fb19f3456d348491e36e9c268ee2278fcebc Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 3 Jun 2019 19:28:35 -0500 Subject: [PATCH 186/348] Adding .DS_Store to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6b65bb21d..a0b059d5b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea/* target/* *.iml -.java-version \ No newline at end of file +.java-version +.DS_Store From 19cd3015f681ced286dcc7e1cacf2072ba1dc627 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 4 Jun 2019 00:02:13 -0500 Subject: [PATCH 187/348] Loosening Lens to simply require Cartesian --- .../palatable/lambda/adt/hmap/Schema.java | 18 ++++++--- .../jnape/palatable/lambda/optics/Lens.java | 38 +++++++++++-------- 2 files changed, 36 insertions(+), 20 deletions(-) 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 index f72b9f8b4..4eee1b0fd 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java @@ -11,8 +11,8 @@ 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.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Both; +import com.jnape.palatable.lambda.functor.Cartesian; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.optics.Lens; @@ -39,8 +39,12 @@ default > Schema add(TypeSafeKe maybeNewValues -> maybeNewValues.fmap(HCons::head))); return new Schema() { @Override - public >, CoF extends Functor>, FB extends Functor, ? extends CoF>, FT extends Functor, PAFB extends Profunctor, FB, ? extends CoP>, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { + public >, + CoF extends Functor>, + FB extends Functor, ? extends CoF>, + FT extends Functor, + PAFB extends Profunctor, FB, ? extends CoP>, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { return lens.apply(pafb); } }; @@ -52,8 +56,12 @@ static Schema> schema(TypeSafeKey key) { .mapB(maybeSingletonA -> maybeSingletonA.fmap(HCons::head)); return new Schema>() { @Override - public >, CoF extends Functor>, FB extends Functor>, ? extends CoF>, FT extends Functor, PAFB extends Profunctor>, FB, ? extends CoP>, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { + public >, + CoF extends Functor>, + FB extends Functor>, ? extends CoF>, + FT extends Functor, + PAFB extends Profunctor>, FB, ? extends CoP>, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { return lens.apply(pafb); } }; diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java index 48e16495c..9f5cbc7f9 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java @@ -5,10 +5,13 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Both; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Cartesian; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.monad.Monad; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.optics.Iso.iso; import static com.jnape.palatable.lambda.optics.Lens.Simple.adapt; import static com.jnape.palatable.lambda.optics.functions.Set.set; @@ -138,7 +141,7 @@ */ @FunctionalInterface public interface Lens extends - Optic, Functor, S, T, A, B>, + Optic, Functor, S, T, A, B>, Monad>, Profunctor> { @@ -269,7 +272,7 @@ default Iso toIso(S s) { * {@inheritDoc} */ @Override - default Lens andThen(Optic, ? super Functor, A, B, C, D> f) { + default Lens andThen(Optic, ? super Functor, A, B, C, D> f) { return lens(Optic.super.andThen(f)); } @@ -277,7 +280,7 @@ default Lens andThen(Optic, ? super Functor * {@inheritDoc} */ @Override - default Lens compose(Optic, ? super Functor, R, U, S, T> g) { + default Lens compose(Optic, ? super Functor, R, U, S, T> g) { return lens(Optic.super.compose(g)); } @@ -294,13 +297,14 @@ default Lens compose(Optic, ? super Functor */ static Lens lens(Fn1 getter, Fn2 setter) { - return lens(Optic., Functor, + return lens(Optic., Functor, S, T, A, B, Functor>, Functor>, - Fn1>>, - Fn1>>>optic(afb -> s -> afb.apply(getter.apply(s)) - .fmap(b -> setter.apply(s, b)))); + Cartesian>, ? extends Cartesian>, + Cartesian>, ? extends Cartesian>>optic( + afb -> afb.cartesian().diMap(s -> tuple(s, getter.apply(s)), + into((s, fb) -> fb.fmap(setter.apply(s)))))); } /** @@ -313,11 +317,14 @@ static Lens lens(Fn1 getter, * @param the type of the "smaller" update value * @return the {@link Lens} */ - static Lens lens(Optic, ? super Functor, S, T, A, B> optic) { + static Lens lens( + Optic, ? super Functor, S, T, A, B> optic) { return new Lens() { @Override - public >, CoF extends Functor>, - FB extends Functor, FT extends Functor, + public >, + CoF extends Functor>, + FB extends Functor, + FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply(PAFB pafb) { return optic.apply(pafb); @@ -378,13 +385,13 @@ static Lens.Simple> both(Lens.Simple f, Lens.Sim * @param the type of both "smaller" values */ @FunctionalInterface - interface Simple extends Lens, Optic.Simple, Functor, S, A> { + interface Simple extends Lens, Optic.Simple, Functor, S, A> { /** * {@inheritDoc} */ @Override - default Lens.Simple andThen(Optic.Simple, ? super Functor, A, B> f) { + default Lens.Simple andThen(Optic.Simple, ? super Functor, A, B> f) { return Lens.Simple.adapt(Lens.super.andThen(f)); } @@ -392,7 +399,7 @@ default Lens.Simple andThen(Optic.Simple, ? super Fu * {@inheritDoc} */ @Override - default Lens.Simple compose(Optic.Simple, ? super Functor, R, S> g) { + default Lens.Simple compose(Optic.Simple, ? super Functor, R, S> g) { return Lens.Simple.adapt(Lens.super.compose(g)); } @@ -404,10 +411,11 @@ default Lens.Simple compose(Optic.Simple, ? super Fu * @param A/B * @return the simple lens */ - static Lens.Simple adapt(Optic, ? super Functor, S, S, A, A> lens) { + static Lens.Simple adapt( + Optic, ? super Functor, S, S, A, A> lens) { return new Lens.Simple() { @Override - public >, + public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply(PAFB pafb) { From f2ce481ca2fc1cfbc6cfee4665fb2234b6ad8238 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 4 Jun 2019 00:27:56 -0500 Subject: [PATCH 188/348] MonadT is now witnessed for better subtyping compatibility --- .../lambda/monad/transformer/MonadT.java | 55 +++++++++---------- .../monad/transformer/builtin/EitherT.java | 12 ++-- .../monad/transformer/builtin/IdentityT.java | 12 ++-- .../monad/transformer/builtin/LazyT.java | 15 ++--- .../monad/transformer/builtin/MaybeT.java | 12 ++-- .../monad/transformer/builtin/ReaderT.java | 12 ++-- .../jnape/palatable/lambda/optics/Prism.java | 7 +-- .../transformer/builtin/ReaderTTest.java | 7 +-- 8 files changed, 64 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java index 17b6dfd4e..1f292ea81 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java @@ -2,29 +2,26 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.transformer.builtin.EitherT; import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT; +import com.jnape.palatable.lambda.monad.transformer.builtin.ReaderT; /** - * An interface representing a {@link Monad} transformer. + * While any two {@link Functor functors} and any two {@link Applicative applicatives} can be composed in general, the + * same is not true in general of any two {@link Monad monads}, in general. However, there exist {@link Monad monads} + * that do compose, in general, with any other {@link Monad}. When this is the case, the combination of these + * {@link Monad monads} with any other {@link Monad} can offer implementations of {@link Monad#pure pure} and + * {@link Monad#flatMap(Fn1) flatMap} for free, simply by relying on the other {@link Monad monad's} implementation of + * both, as well as their own privileged knowledge about how to merge the nested {@link Monad#flatMap(Fn1) flatMap} + * call. This can be thought of as "gluing" together two {@link Monad monads}, allowing easier access to their values, + * as well as, in some cases, providing universally correct constructions of the composed short-circuiting algorithms. *

- * While any two {@link com.jnape.palatable.lambda.functor.Functor functors} and any two - * {@link Applicative applicatives} can be composed in general, the same is not true in general of any two - * {@link Monad monads}. However, there exist {@link Monad monads} that do compose, in general, with any other - * {@link Monad}, provided that they are embedded inside the other {@link Monad}. When this is the case, they can offer - * implementations of {@link Monad#pure pure} and {@link Monad#flatMap(Fn1) flatMap} for free, simply by relying - * on the outer {@link Monad monad's} implementation of both, as well as their own privileged knowledge about how to - * merge the nested {@link Monad#flatMap(Fn1) flatMap} call. - *

- * The term "monad transformer" describes a particular encoding of monadic composition. Because this general composition - * of a particular {@link Monad} with any other {@link Monad} relies on privileged knowledge about the embedded - * {@link Monad}, the {@link MonadT transformer} representing this compositions is described from the embedded - * {@link Monad monad's} perspective (e.g. {@link MaybeT} describing the embedding - * {@link Monad}<{@link com.jnape.palatable.lambda.adt.Maybe}<A>>). - *

- * Additionally, monad transformers connected by compatible {@link Monad monads} also compose. When two or more monad - * transformers are composed, this is generally referred to as a "monad transformer stack". + * The term "monad transformer" describes this particular encoding of monadic composition, and tends to be + * named in terms of {@link Monad} for which privileged knowledge must be known in order to eliminate during + * {@link Monad#flatMap(Fn1) flatmapping}. *

* For more information, read more about * monad transformers. @@ -33,9 +30,11 @@ * @param the inner {@link Monad monad} * @param the carrier type * @see MaybeT + * @see EitherT + * @see ReaderT */ -public interface MonadT, G extends Monad, A> - extends Monad> { +public interface MonadT, G extends Monad, A, MT extends MonadT> + extends Monad { /** * Extract out the composed monad out of this transformer. @@ -50,19 +49,19 @@ public interface MonadT, G extends Monad, A> * {@inheritDoc} */ @Override - MonadT flatMap(Fn1>> f); + MonadT flatMap(Fn1> f); /** * {@inheritDoc} */ @Override - MonadT pure(B b); + MonadT pure(B b); /** * {@inheritDoc} */ @Override - default MonadT fmap(Fn1 fn) { + default MonadT fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -70,7 +69,7 @@ default MonadT fmap(Fn1 fn) { * {@inheritDoc} */ @Override - default MonadT zip(Applicative, MonadT> appFn) { + default MonadT zip(Applicative, MT> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -78,16 +77,16 @@ default MonadT zip(Applicative, MonadT< * {@inheritDoc} */ @Override - default Lazy> lazyZip( - Lazy, MonadT>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + default Lazy> lazyZip( + Lazy, MT>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad::coerce); } /** * {@inheritDoc} */ @Override - default MonadT discardL(Applicative> appB) { + default MonadT discardL(Applicative appB) { return Monad.super.discardL(appB).coerce(); } @@ -95,7 +94,7 @@ default MonadT discardL(Applicative> appB) { * {@inheritDoc} */ @Override - default MonadT discardR(Applicative> appB) { + default MonadT discardR(Applicative appB) { return Monad.super.discardR(appB).coerce(); } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java index 7b1cb0deb..f3f26adba 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -23,7 +23,7 @@ */ public final class EitherT, L, R> implements Bifunctor>, - MonadT, R> { + MonadT, R, EitherT> { private final Monad, M> melr; @@ -43,7 +43,7 @@ private EitherT(Monad, M> melr) { * {@inheritDoc} */ @Override - public EitherT flatMap(Fn1, ?>>> f) { + public EitherT flatMap(Fn1>> f) { return eitherT(melr.flatMap(lr -> lr.match(l -> melr.pure(left(l)), r -> f.apply(r).>coerce().run()))); } @@ -69,7 +69,7 @@ public EitherT fmap(Fn1 fn) { */ @Override public EitherT zip( - Applicative, MonadT, ?>> appFn) { + Applicative, EitherT> appFn) { return MonadT.super.zip(appFn).coerce(); } @@ -78,7 +78,7 @@ public EitherT zip( */ @Override public Lazy> lazyZip( - Lazy, MonadT, ?>>> lazyAppFn) { + Lazy, EitherT>> lazyAppFn) { return new Compose<>(melr) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( maybeT.>>coerce() @@ -91,7 +91,7 @@ public Lazy> lazyZip( * {@inheritDoc} */ @Override - public EitherT discardL(Applicative, ?>> appB) { + public EitherT discardL(Applicative> appB) { return MonadT.super.discardL(appB).coerce(); } @@ -99,7 +99,7 @@ public EitherT discardL(Applicative, ? * {@inheritDoc} */ @Override - public EitherT discardR(Applicative, ?>> appB) { + public EitherT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java index a3e87e3fc..16bf78db5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java @@ -16,7 +16,7 @@ * @param the outer {@link Monad} * @param the carrier type */ -public final class IdentityT, A> implements MonadT, A> { +public final class IdentityT, A> implements MonadT, A, IdentityT> { private final Monad, M> mia; @@ -36,7 +36,7 @@ public >, FGA extends Monad> FGA run() { * {@inheritDoc} */ @Override - public IdentityT flatMap(Fn1, ?>>> f) { + public IdentityT flatMap(Fn1>> f) { return identityT(mia.flatMap(identityA -> f.apply(identityA.runIdentity()).>coerce().run())); } @@ -60,7 +60,7 @@ public IdentityT fmap(Fn1 fn) { * {@inheritDoc} */ @Override - public IdentityT zip(Applicative, MonadT, ?>> appFn) { + public IdentityT zip(Applicative, IdentityT> appFn) { return MonadT.super.zip(appFn).coerce(); } @@ -69,7 +69,7 @@ public IdentityT zip(Applicative, MonadT Lazy> lazyZip( - Lazy, MonadT, ?>>> lazyAppFn) { + Lazy, IdentityT>> lazyAppFn) { return new Compose<>(mia) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( maybeT.>>coerce() @@ -82,7 +82,7 @@ public Lazy> lazyZip( * {@inheritDoc} */ @Override - public IdentityT discardL(Applicative, ?>> appB) { + public IdentityT discardL(Applicative> appB) { return MonadT.super.discardL(appB).coerce(); } @@ -90,7 +90,7 @@ public IdentityT discardL(Applicative, ?>> ap * {@inheritDoc} */ @Override - public IdentityT discardR(Applicative, ?>> appB) { + public IdentityT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java index d35ddc215..512118edc 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java @@ -18,7 +18,7 @@ * @param the outer {@link Monad} * @param the carrier type */ -public class LazyT, A> implements MonadT, A> { +public class LazyT, A> implements MonadT, A, LazyT> { private final Monad, M> mla; @@ -38,8 +38,9 @@ public >, FGA extends Monad> FGA run() { * {@inheritDoc} */ @Override - public LazyT flatMap(Fn1, ?>>> f) { - return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value())., B>>coerce().run())); + public LazyT flatMap(Fn1>> f) { + return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value()) + ., B, LazyT>>coerce().run())); } /** @@ -62,7 +63,7 @@ public LazyT fmap(Fn1 fn) { * {@inheritDoc} */ @Override - public LazyT zip(Applicative, MonadT, ?>> appFn) { + public LazyT zip(Applicative, LazyT> appFn) { return MonadT.super.zip(appFn).coerce(); } @@ -71,7 +72,7 @@ public LazyT zip(Applicative, MonadT Lazy> lazyZip( - Lazy, MonadT, ?>>> lazyAppFn) { + Lazy, LazyT>> lazyAppFn) { return new Compose<>(mla) .lazyZip(lazyAppFn.fmap(lazyT -> new Compose<>( lazyT.>>coerce() @@ -84,7 +85,7 @@ public Lazy> lazyZip( * {@inheritDoc} */ @Override - public LazyT discardL(Applicative, ?>> appB) { + public LazyT discardL(Applicative> appB) { return MonadT.super.discardL(appB).coerce(); } @@ -92,7 +93,7 @@ public LazyT discardL(Applicative, ?>> appB) { * {@inheritDoc} */ @Override - public LazyT discardR(Applicative, ?>> appB) { + public LazyT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index 7f1cf151f..09938d01e 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -20,7 +20,7 @@ * @param the outer {@link Monad} * @param the carrier type */ -public final class MaybeT, A> implements MonadT, A> { +public final class MaybeT, A> implements MonadT, A, MaybeT> { private final Monad, M> mma; @@ -56,7 +56,7 @@ public MaybeT pure(B b) { * {@inheritDoc} */ @Override - public MaybeT zip(Applicative, MonadT, ?>> appFn) { + public MaybeT zip(Applicative, MaybeT> appFn) { return MonadT.super.zip(appFn).coerce(); } @@ -65,7 +65,7 @@ public MaybeT zip(Applicative, MonadT Lazy> lazyZip( - Lazy, MonadT, ?>>> lazyAppFn) { + Lazy, MaybeT>> lazyAppFn) { return new Compose<>(mma) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( maybeT.>>coerce() @@ -77,7 +77,7 @@ public Lazy> lazyZip( * {@inheritDoc} */ @Override - public MaybeT flatMap(Fn1, ?>>> f) { + public MaybeT flatMap(Fn1>> f) { return maybeT(mma.flatMap(ma -> ma .match(constantly(mma.pure(nothing())), a -> f.apply(a).>coerce().run()))); @@ -87,7 +87,7 @@ public MaybeT flatMap(Fn1 MaybeT discardL(Applicative, ?>> appB) { + public MaybeT discardL(Applicative> appB) { return MonadT.super.discardL(appB).coerce(); } @@ -95,7 +95,7 @@ public MaybeT discardL(Applicative, ?>> appB) { * {@inheritDoc} */ @Override - public MaybeT discardR(Applicative, ?>> appB) { + public MaybeT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index e38ece76d..d905236f0 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -20,7 +20,7 @@ * @param the embedded output type */ public interface ReaderT, A> extends - MonadT, M, A>, + MonadT, M, A, ReaderT>, Cartesian> { /** @@ -57,7 +57,7 @@ default , N extends Monad, B> ReaderT mapR * {@inheritDoc} */ @Override - default ReaderT flatMap(Fn1, M, ?>>> f) { + default ReaderT flatMap(Fn1>> f) { return readerT(r -> runReaderT(r).flatMap(a -> f.apply(a).>coerce().runReaderT(r))); } @@ -81,7 +81,7 @@ default ReaderT fmap(Fn1 fn) { * {@inheritDoc} */ @Override - default ReaderT zip(Applicative, MonadT, M, ?>> appFn) { + default ReaderT zip(Applicative, ReaderT> appFn) { return readerT(r -> runReaderT(r).zip(appFn.>>coerce().runReaderT(r))); } @@ -90,7 +90,7 @@ default ReaderT zip(Applicative, MonadT */ @Override default Lazy> lazyZip( - Lazy, MonadT, M, ?>>> lazyAppFn) { + Lazy, ReaderT>> lazyAppFn) { return lazyAppFn.fmap(this::zip); } @@ -98,7 +98,7 @@ default Lazy> lazyZip( * {@inheritDoc} */ @Override - default ReaderT discardL(Applicative, M, ?>> appB) { + default ReaderT discardL(Applicative> appB) { return MonadT.super.discardL(appB).coerce(); } @@ -106,7 +106,7 @@ default ReaderT discardL(Applicative, M, ?>> ap * {@inheritDoc} */ @Override - default ReaderT discardR(Applicative, M, ?>> appB) { + default ReaderT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java index c15f2185f..c76161413 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -24,9 +24,11 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; import static com.jnape.palatable.lambda.optics.Prism.Simple.adapt; import static com.jnape.palatable.lambda.optics.functions.Matching.matching; import static com.jnape.palatable.lambda.optics.functions.Re.re; +import static com.jnape.palatable.lambda.optics.functions.View.view; /** * Prisms are {@link Iso Isos} that can fail in one direction. Example: @@ -64,10 +66,7 @@ public interface Prism extends * @return a {@link Tuple2 tuple} of the two mappings encapsulated by this {@link Prism} */ default Tuple2, Fn1>> unPrism() { - return Tuple2.fill(this., Identity, Identity, Identity, - Market>, Market>>apply( - new Market<>(Identity::new, Either::right)).fmap(Identity::runIdentity)) - .biMap(Market::bt, Market::sta); + return both(Re.re().fmap(view()), matching(), this); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java index aedd4a47a..80af55802 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java @@ -1,10 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.builtin.Identity; -import com.jnape.palatable.lambda.monad.Monad; -import com.jnape.palatable.lambda.monad.transformer.MonadT; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -22,9 +19,9 @@ public class ReaderTTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, Identity, ?>, Integer> testSubject() { + public EquatableM, ?>, Integer> testSubject() { return new EquatableM<>(readerT(Identity::new), - readerT -> ((Fn1>>) readerT.run()).apply(1)); + readerT -> readerT.runReaderT(1)); } @Test From c5878f417352b8c9d40cb6a6c7990b48a2a0f364 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 4 Jun 2019 00:33:20 -0500 Subject: [PATCH 189/348] Alter requires only Fn1 now --- CHANGELOG.md | 6 +++++- .../jnape/palatable/lambda/functions/builtin/fn2/Alter.java | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6396ed612..b5571f431 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] +### Changed +- `MonadT` is now witnessed by a parameter for better subtyping +- `Alter` now merely requires an `Fn1` instead of an explicit `Effect` + ### Added - `Optic#andThen`, `Optic#compose`, and other defaults added - `Prism#andThen`, `Prism#compose` begets another `Prism` - `Prism#fromPartial` public interfaces -- `ReaderT`, the transformer for the reader monad +- `ReaderT`, the transformer for the reader monad ## [4.0.0] - 2019-05-20 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java index 5eb0b2cc4..b830a7e9c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -13,7 +13,7 @@ * * @param the input and output */ -public final class Alter implements Fn2, A, IO> { +public final class Alter implements Fn2>, A, IO> { private static final Alter INSTANCE = new Alter<>(); @@ -21,7 +21,7 @@ private Alter() { } @Override - public IO checkedApply(Effect effect, A a) { + public IO checkedApply(Fn1> effect, A a) { return effect.fmap(io -> io.fmap(constantly(a))).apply(a); } From 2885fb99f4100372aae2c14f38c868078305f991 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 4 Jun 2019 18:20:11 -0500 Subject: [PATCH 190/348] Loosening Pre's requirements on the Profunctor constraint --- .../lambda/optics/functions/Pre.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java index 977788eac..f7d3c4095 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Pre.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.functor.builtin.Const; import com.jnape.palatable.lambda.optics.Optic; import com.jnape.palatable.lambda.optics.ProtoOptic; @@ -19,42 +20,41 @@ * @param the result to {@link Maybe maybe} read out * @param used for unification of the {@link Optic optic's} unused morphism */ -public final class Pre implements Fn1, ? super Const, ?>, S, T, A, B>, - Optic, Const, ?>, S, T, Maybe, B>> { +public final class Pre

, S, T, A, B> implements + Fn1, ?>, S, T, A, B>, + Optic, ?>, S, T, Maybe, B>> { - private static final Pre INSTANCE = new Pre<>(); + private static final Pre INSTANCE = new Pre<>(); private Pre() { } @Override - public Optic, Const, ?>, S, T, Maybe, B> checkedApply( - Optic, ? super Const, ?>, S, T, A, B> optic) { - Optic, ? super Const, ?>, S, T, Maybe, B> mappedOptic = optic.mapA(Maybe::just); + public Optic, ?>, S, T, Maybe, B> checkedApply( + Optic, ?>, S, T, A, B> optic) { + Optic, ?>, S, T, Maybe, B> mappedOptic = optic.mapA(Maybe::just); return reframe(mappedOptic); } @SuppressWarnings("unchecked") - public static Pre pre() { - return (Pre) INSTANCE; + public static

, S, T, A, B> Pre pre() { + return (Pre) INSTANCE; } @SuppressWarnings("overloads") - public static Optic, Const, ?>, S, T, Maybe, B> pre( - Optic, ? super Const, ?>, S, T, A, B> optic) { - return Pre.pre().apply(optic); + public static

, S, T, A, B> + Optic, ?>, S, T, Maybe, B> pre(Optic, ?>, S, T, A, B> optic) { + return Pre.pre().apply(optic); } @SuppressWarnings("overloads") - public static Optic, Const, ?>, S, T, Maybe, B> pre( - ProtoOptic, S, T, A, B> protoOptic) { - Optic, Const, ?>, S, T, A, B> optic = protoOptic - .toOptic(new Pure, ?>>() { - @Override - public Const, X> checkedApply(X x) { - return new Const<>(nothing()); - } - }); - return pre(optic); + public static

, S, T, A, B> + Optic, ?>, S, T, Maybe, B> pre(ProtoOptic protoOptic) { + return pre(protoOptic.toOptic(new Pure, ?>>() { + @Override + public Const, X> checkedApply(X x) { + return new Const<>(nothing()); + } + })); } } \ No newline at end of file From f0dfd2d9c4137ef589ca91f5e0c30ea3786f0b43 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 8 Jun 2019 16:33:37 -0500 Subject: [PATCH 191/348] Re now returns an Optic that imposes no profunctor constraint --- .../palatable/lambda/optics/functions/Re.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java b/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java index eeb36f5b8..a948a0170 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/functions/Re.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.optics.functions; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.functor.builtin.Const; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.lambda.functor.builtin.Tagged; @@ -18,7 +19,8 @@ * @param the value to read from */ public final class Re implements - Fn1, ? super Identity, S, T, A, B>, Optic, Const, B, B, T, T>> { + Fn1, ? super Identity, S, T, A, B>, + Optic, Const, B, B, T, T>> { private static final Re INSTANCE = new Re<>(); @@ -26,14 +28,17 @@ private Re() { } @Override - public Optic, Const, B, B, T, T> checkedApply( + public Optic, Const, B, B, T, T> checkedApply( Optic, ? super Identity, S, T, A, B> optic) { - return Optic., Const, B, B, T, T, + return Optic., Const, B, B, T, T, Const, Const, - Fn1>, - Fn1>>optic(pafb -> b -> new Const<>(optic., Identity, Identity, - Identity, Tagged>, - Tagged>>apply(new Tagged<>(new Identity<>(b))).unTagged().runIdentity())); + Profunctor, ? extends Profunctor>, + Profunctor, ? extends Profunctor>>optic( + pafb -> pafb.diMap( + b -> optic., Identity, Identity, Identity, + Tagged>, Tagged>>apply( + new Tagged<>(new Identity<>(b))).unTagged().runIdentity(), + fb -> new Const<>(fb.runConst()))); } @SuppressWarnings("unchecked") @@ -41,7 +46,7 @@ public static Re re() { return (Re) INSTANCE; } - public static Optic, Const, B, B, T, T> re( + public static Optic, Const, B, B, T, T> re( Optic, ? super Identity, S, T, A, B> optic) { return Re.re().apply(optic); } From bf5066ee61aed12d9787d91ebcf95a5959caf93c Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 16 Jun 2019 20:33:36 -0500 Subject: [PATCH 192/348] Apparently I must now pin to Trusty for Travis to build against jdk8 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8ea4e5783..a8ca1b4c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +dist: trusty language: java jdk: - oraclejdk8 From 7386733575dc652cc9da598c577c1889e1b4e2ee Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 18 Jun 2019 21:36:46 -0500 Subject: [PATCH 193/348] Updating Travis badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 18584232d..57b765ff7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ λ ====== -[![Build Status](https://img.shields.io/travis/palatable/lambda/master.svg)](https://travis-ci.org/palatable/lambda) +[![Build Status](https://travis-ci.com/palatable/lambda.svg?branch=master)](https://travis-ci.com/palatable/lambda) [![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda) [![Join the chat at https://gitter.im/palatable/lambda](https://badges.gitter.im/palatable/lambda.svg)](https://gitter.im/palatable/lambda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) From 9c944e51feab09bd98a0a347128287c16dfd3da7 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 22 Jun 2019 15:16:01 -0500 Subject: [PATCH 194/348] LazyRec explicitly injects a proper Kleisli arrow into the caller fn --- .../lambda/functions/builtin/fn2/LazyRec.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java index 7ebb8fe6f..c1b7253d2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/LazyRec.java @@ -1,11 +1,11 @@ package com.jnape.palatable.lambda.functions.builtin.fn2; -import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.specialized.Kleisli; import com.jnape.palatable.lambda.functor.builtin.Lazy; +import static com.jnape.palatable.lambda.functions.specialized.Kleisli.kleisli; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; -import static com.jnape.palatable.lambda.monad.Monad.join; /** * Given a {@link Fn2} that receives a recursive function and an input and yields a {@link Lazy lazy} result, and an @@ -26,7 +26,8 @@ * @param the input type * @param the output type */ -public final class LazyRec implements Fn2>, A, Lazy>, A, Lazy> { +public final class LazyRec implements + Fn2, Lazy>, A, Lazy>, A, Lazy> { private static final LazyRec INSTANCE = new LazyRec<>(); @@ -34,8 +35,8 @@ private LazyRec() { } @Override - public Lazy checkedApply(Fn2>, A, Lazy> fn, A a) { - return join(lazy(() -> fn.apply(nextA -> apply(fn, nextA), a))); + public Lazy checkedApply(Fn2, Lazy>, A, Lazy> fn, A a) { + return lazy(a).flatMap(fn.apply(lazyRec(fn))); } @SuppressWarnings("unchecked") @@ -43,11 +44,12 @@ public static LazyRec lazyRec() { return (LazyRec) INSTANCE; } - public static Fn1> lazyRec(Fn2>, A, Lazy> fn) { - return LazyRec.lazyRec().apply(fn); + public static Kleisli, Lazy> lazyRec( + Fn2, Lazy>, A, Lazy> fn) { + return kleisli(LazyRec.lazyRec().apply(fn)); } - public static Lazy lazyRec(Fn2>, A, Lazy> fn, A a) { + public static Lazy lazyRec(Fn2, Lazy>, A, Lazy> fn, A a) { return lazyRec(fn).apply(a); } } From 866731cc7e0679ee5e35c50a60a5192daa7d7d28 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 16 Jun 2019 20:13:09 -0500 Subject: [PATCH 195/348] All forms of IO composition are now stack-safe - sequencing large (non-infinite!) iterables of IOs will eagerly fold all IOs into a single IO that can parallelize every step --- CHANGELOG.md | 3 + .../com/jnape/palatable/lambda/io/IO.java | 112 +++++------- .../com/jnape/palatable/lambda/io/IOTest.java | 166 ++++++++++++------ 3 files changed, 160 insertions(+), 121 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5571f431..adad50772 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - `MonadT` is now witnessed by a parameter for better subtyping - `Alter` now merely requires an `Fn1` instead of an explicit `Effect` +- `IO` now internally trampolines all forms of composition, including lazyZip; + sequencing very large iterables of IO will work, if you have the heap, and + retain parallelization inflection points ### Added - `Optic#andThen`, `Optic#compose`, and other defaults added diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index c86fcbc59..9bfb586e6 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -4,28 +4,24 @@ import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.choice.Choice2; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn2.LazyRec; import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; -import java.util.LinkedList; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; -import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; -import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; -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 com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.monad.Monad.join; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.CompletableFuture.supplyAsync; @@ -142,20 +138,16 @@ public final IO fmap(Fn1 fn) { * {@inheritDoc} */ @Override - public final IO zip(Applicative, IO> appFn) { - @SuppressWarnings("unchecked") - IO source = (IO) this; - @SuppressWarnings("unchecked") - IO> zip = (IO>) (Object) appFn; - return new Compose<>(source, a(zip)); + public IO zip(Applicative, IO> appFn) { + return new Compose<>(this, a((IO>) appFn)); } /** * {@inheritDoc} */ @Override - public Lazy> lazyZip(Lazy, IO>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + public final Lazy> lazyZip(Lazy, IO>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).>fmap(Functor::coerce).coerce(); } /** @@ -179,11 +171,9 @@ public final IO discardR(Applicative> appB) { */ @Override public final IO flatMap(Fn1>> f) { - @SuppressWarnings("unchecked") - IO source = (IO) this; @SuppressWarnings({"unchecked", "RedundantCast"}) - Fn1> flatMap = (Fn1>) (Object) f; - return new Compose<>(source, Choice2.b(flatMap)); + Choice2, Fn1>> composition = Choice2.b((Fn1>) (Object) f); + return new Compose<>(this, composition); } /** @@ -279,61 +269,55 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { } private static final class Compose extends IO { - private final IO source; - private final Choice2>, Fn1>> composition; - private Compose(IO source, Choice2>, Fn1>> composition) { + private final IO source; + private final Choice2, Fn1>> composition; + + private Compose(IO source, Choice2, Fn1>> composition) { this.source = source; this.composition = composition; } @Override public A unsafePerformIO() { - @SuppressWarnings("unchecked") - A result = (A) trampoline(into((source, compositions) -> { - Object res = source.unsafePerformIO(); - return compositions.isEmpty() - ? terminate(res) - : compositions.pop().match( - zip -> recurse(tuple(io(zip.unsafePerformIO().apply(res)), compositions)), - flatMap -> { - IO next = flatMap.apply(res); - return (next instanceof Compose) - ? recurse(((Compose) next).deforest(compositions)) - : recurse(tuple(next, compositions)); - }); - }), deforest(new LinkedList<>())); - - return result; + Lazy lazyA = LazyRec., Object>lazyRec( + (f, io) -> { + if (io instanceof IO.Compose) { + Compose compose = (Compose) io; + Lazy head = f.apply(compose.source); + return compose.composition + .match(zip -> head.flatMap(x -> f.apply(zip) + .>fmap(downcast()) + .fmap(g -> g.apply(x))), + flatMap -> head.fmap(flatMap).flatMap(f)); + } + return lazy(io::unsafePerformIO); + }, + this); + return downcast(lazyA.value()); } @Override + @SuppressWarnings("unchecked") public CompletableFuture unsafePerformAsyncIO(Executor executor) { - @SuppressWarnings("unchecked") - CompletableFuture future = (CompletableFuture) deforest(new LinkedList<>()) - .into((source, compositions) -> foldLeft( - (ioFuture, composition) -> composition - .match(zip -> zip.unsafePerformAsyncIO(executor) - .thenComposeAsync(f -> ioFuture.thenApply(f.toFunction()), executor), - flatMap -> ioFuture.thenComposeAsync(obj -> flatMap.apply(obj) - .unsafePerformAsyncIO(executor), executor)), - source.unsafePerformAsyncIO(executor), - compositions)); - return future; - } - - private Tuple2, LinkedList>, Fn1>>>> - deforest(LinkedList>, Fn1>>> branches) { - Tuple2, LinkedList>, Fn1>>>> args = - tuple(this, branches); - return trampoline(into((source, compositions) -> { - IO leaf = source.source; - compositions.push(source.composition); - return leaf instanceof Compose - ? recurse(tuple((Compose) leaf, compositions)) - : terminate(tuple(leaf, compositions)); - }), args); + Lazy> lazyFuture = LazyRec., CompletableFuture>lazyRec( + (f, io) -> { + if (io instanceof IO.Compose) { + Compose compose = (Compose) io; + Lazy> head = f.apply(compose.source); + return compose.composition + .match(zip -> head.flatMap(futureX -> f.apply(zip) + .fmap(futureF -> futureF.thenCompose(f2 -> futureX + .thenApply(((Fn1) f2).toFunction())))), + flatMap -> head.fmap(futureX -> futureX + .thenComposeAsync(x -> f.apply(flatMap.apply(x)).value(), + executor))); + } + return lazy(() -> (CompletableFuture) io.unsafePerformAsyncIO(executor)); + }, + this); + + return (CompletableFuture) lazyFuture.value(); } - } } diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 2c86683e3..3dc288ec0 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -1,7 +1,9 @@ package com.jnape.palatable.lambda.io; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn2.Sequence; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -21,13 +23,17 @@ import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.io.IO.externallyManaged; import static com.jnape.palatable.lambda.io.IO.io; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.Executors.newFixedThreadPool; import static java.util.concurrent.ForkJoinPool.commonPool; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -126,63 +132,6 @@ public void exceptionallyRescuesFutures() { assertEquals("foo", externallyManaged.unsafePerformIO()); } - @Test - public void linearSyncStackSafety() { - assertEquals(STACK_EXPLODING_NUMBER, - times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), io(0)).unsafePerformIO()); - assertEquals(STACK_EXPLODING_NUMBER, - times(STACK_EXPLODING_NUMBER, f -> f.zip(f.pure(x -> x + 1)), io(0)).unsafePerformIO()); - assertEquals((Integer) 0, - times(STACK_EXPLODING_NUMBER, f -> f.pure(0).discardR(f), io(0)).unsafePerformIO()); - assertEquals((Integer) 1, - times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardR(f), io(0)).unsafePerformIO()); - assertEquals((Integer) 0, - times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardL(f), io(0)).unsafePerformIO()); - assertEquals(STACK_EXPLODING_NUMBER, - times(STACK_EXPLODING_NUMBER, f -> f.flatMap(x -> f.pure(x + 1)), io(0)).unsafePerformIO()); - } - - @Test - public void recursiveSyncFlatMapStackSafety() { - assertEquals(STACK_EXPLODING_NUMBER, - new Fn1, IO>() { - @Override - public IO checkedApply(IO a) { - return a.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(io(x + 1)) : io(x)); - } - }.apply(io(0)).unsafePerformIO()); - - } - - @Test - public void linearAsyncStackSafety() { - assertEquals(STACK_EXPLODING_NUMBER, - times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), io(0)).unsafePerformAsyncIO().join()); - assertEquals(STACK_EXPLODING_NUMBER, - times(STACK_EXPLODING_NUMBER, f -> f.zip(f.pure(x -> x + 1)), io(0)).unsafePerformAsyncIO() - .join()); - assertEquals((Integer) 0, - times(STACK_EXPLODING_NUMBER, f -> f.pure(0).discardR(f), io(0)).unsafePerformAsyncIO().join()); - assertEquals((Integer) 1, - times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardR(f), io(0)).unsafePerformAsyncIO().join()); - assertEquals((Integer) 0, - times(STACK_EXPLODING_NUMBER, f -> f.pure(1).discardL(f), io(0)).unsafePerformAsyncIO().join()); - assertEquals(STACK_EXPLODING_NUMBER, - times(STACK_EXPLODING_NUMBER, f -> f.flatMap(x -> f.pure(x + 1)), io(0)).unsafePerformAsyncIO() - .join()); - } - - @Test - public void recursiveAsyncFlatMapStackSafety() { - assertEquals(STACK_EXPLODING_NUMBER, - new Fn1, IO>() { - @Override - public IO checkedApply(IO a) { - return a.flatMap(x -> x < STACK_EXPLODING_NUMBER ? apply(io(x + 1)) : io(x)); - } - }.apply(io(0)).unsafePerformAsyncIO().join()); - } - @Test public void safe() { assertEquals(right(1), io(() -> 1).safe().unsafePerformIO()); @@ -243,4 +192,107 @@ public void throwing() { assertEquals(expected, actual); } } + + @Test + public void zipStackSafety() { + IO> zipAdd1 = io(x -> x + 1); + IO zero = io(0); + + IO leftHeavy = times(STACK_EXPLODING_NUMBER, io -> io.zip(zipAdd1), zero); + assertEquals(STACK_EXPLODING_NUMBER, leftHeavy.unsafePerformIO()); + assertEquals(STACK_EXPLODING_NUMBER, leftHeavy.unsafePerformAsyncIO().join()); + + IO rightHeavy = times(STACK_EXPLODING_NUMBER, io -> zipAdd1.zip(io.fmap(x -> f -> f.apply(x))), zero); + assertEquals(STACK_EXPLODING_NUMBER, rightHeavy.unsafePerformIO()); + assertEquals(STACK_EXPLODING_NUMBER, rightHeavy.unsafePerformAsyncIO().join()); + } + + @Test + public void discardStackSafety() { + IO discardL = times(STACK_EXPLODING_NUMBER, io -> io(1).discardL(io), io(0)); + assertEquals((Integer) 0, discardL.unsafePerformIO()); + assertEquals((Integer) 0, discardL.unsafePerformAsyncIO().join()); + + IO discardR = times(STACK_EXPLODING_NUMBER, io -> io.discardR(io(1)), io(0)); + assertEquals((Integer) 0, discardR.unsafePerformIO()); + assertEquals((Integer) 0, discardR.unsafePerformAsyncIO().join()); + } + + @Test + public void lazyZipStackSafety() { + IO> zipAdd1 = io(x -> x + 1); + IO zero = io(0); + + IO leftHeavy = times(STACK_EXPLODING_NUMBER, io -> io.lazyZip(lazy(zipAdd1)).value(), zero); + assertEquals(STACK_EXPLODING_NUMBER, leftHeavy.unsafePerformIO()); + assertEquals(STACK_EXPLODING_NUMBER, leftHeavy.unsafePerformAsyncIO().join()); + + IO rightHeavy = times(STACK_EXPLODING_NUMBER, + io -> zipAdd1.lazyZip(lazy(io.fmap(x -> f -> f.apply(x)))).value(), + zero); + assertEquals(STACK_EXPLODING_NUMBER, rightHeavy.unsafePerformIO()); + assertEquals(STACK_EXPLODING_NUMBER, rightHeavy.unsafePerformAsyncIO().join()); + } + + @Test + public void flatMapStackSafety() { + Fn1> add1 = x -> io(() -> x + 1); + IO zero = io(0); + + IO leftHeavy = times(STACK_EXPLODING_NUMBER, io -> io.flatMap(add1), zero); + assertEquals(STACK_EXPLODING_NUMBER, leftHeavy.unsafePerformIO()); + assertEquals(STACK_EXPLODING_NUMBER, leftHeavy.unsafePerformAsyncIO().join()); + + IO rightHeavy = times(STACK_EXPLODING_NUMBER, + io -> add1.apply(0).flatMap(x -> io.fmap(y -> x + y)), + zero); + assertEquals(STACK_EXPLODING_NUMBER, rightHeavy.unsafePerformIO()); + assertEquals(STACK_EXPLODING_NUMBER, rightHeavy.unsafePerformAsyncIO().join()); + } + + @Test + public void staggeredZipAndFlatMapStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, io -> io.zip(io(x -> x + 1)) + .flatMap(x -> io(() -> x)) + .zip(io(x -> x)), io(0)) + .unsafePerformIO()); + } + + @Test + public void sequenceStackSafety() { + assertEquals(STACK_EXPLODING_NUMBER, + Sequence.sequence(replicate(STACK_EXPLODING_NUMBER, io(UNIT)), IO::io) + .fmap(size()) + .fmap(Long::intValue) + .unsafePerformIO()); + + assertEquals(STACK_EXPLODING_NUMBER, + Sequence.sequence(replicate(STACK_EXPLODING_NUMBER, io(UNIT)), IO::io) + .fmap(size()) + .fmap(Long::intValue) + .unsafePerformAsyncIO().join()); + } + + @Test + public void sequenceIOExecutesInParallel() { + int n = 2; + CountDownLatch latch = new CountDownLatch(n); + Sequence.sequence(replicate(n, io(() -> { + latch.countDown(); + if (!latch.await(100, MILLISECONDS)) { + throw new AssertionError("Expected latch to countDown in time, but didn't."); + } + })), IO::io) + .unsafePerformAsyncIO() + .join(); + } + + @Test + public void sequenceIsRepeatable() { + IO> io = Sequence.sequence(replicate(3, io(UNIT)), IO::io); + + assertEquals((Long) 3L, size(io.unsafePerformIO())); + assertEquals((Long) 3L, size(io.unsafePerformIO())); + } } \ No newline at end of file From e3d13b74cb961f217fb5b679102ce3fb4a94b340 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 22 Jun 2019 17:21:10 -0500 Subject: [PATCH 196/348] Until, for repeatedly running an IO until a predicate matches its value --- CHANGELOG.md | 3 +- .../lambda/functions/builtin/fn2/Until.java | 40 +++++++++++++++++++ .../functions/builtin/fn2/UntilTest.java | 24 +++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Until.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UntilTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index adad50772..49ec83bbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Optic#andThen`, `Optic#compose`, and other defaults added - `Prism#andThen`, `Prism#compose` begets another `Prism` - `Prism#fromPartial` public interfaces -- `ReaderT`, the transformer for the reader monad +- `ReaderT`, the transformer for the reader monad +- `Until`, for repeatedly executing an `IO` until its result matches a predicate ## [4.0.0] - 2019-05-20 ### Changed diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Until.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Until.java new file mode 100644 index 000000000..be5b1f5b4 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Until.java @@ -0,0 +1,40 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.io.IO; + +import static com.jnape.palatable.lambda.io.IO.io; + +/** + * Given a {@link Fn1 predicate function} for a value of some type A and an {@link IO} that yields a value + * of type A, produce an {@link IO} that repeatedly executes the original {@link IO} until the predicate + * returns true when applied to the yielded value. + * + * @param the {@link IO} value type + */ +public final class Until implements Fn2, IO, IO> { + + private static final Until INSTANCE = new Until<>(); + + private Until() { + } + + @Override + public IO checkedApply(Fn1 pred, IO io) { + return io.flatMap(a -> pred.apply(a) ? io(a) : until(pred, io)); + } + + @SuppressWarnings("unchecked") + public static Until until() { + return (Until) INSTANCE; + } + + public static Fn1, IO> until(Fn1 pred) { + return Until.until().apply(pred); + } + + public static IO until(Fn1 pred, IO io) { + return Until.until(pred).apply(io); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UntilTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UntilTest.java new file mode 100644 index 000000000..3a6e1e953 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UntilTest.java @@ -0,0 +1,24 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Until.until; +import static com.jnape.palatable.lambda.io.IO.io; +import static org.junit.Assert.assertEquals; + +public class UntilTest { + + @Test + public void repeatedlyExecutesUntilPredicateMatches() { + AtomicInteger counter = new AtomicInteger(0); + assertEquals((Integer) 10, until(x -> x == 10, io(counter::getAndIncrement)).unsafePerformIO()); + } + + @Test + public void predicateThatImmediatelyMatchesDoesNotChangeIO() { + assertEquals((Integer) 0, until(constantly(true), io(0)).unsafePerformIO()); + } +} \ No newline at end of file From ca3e6db08acc0c92bddb01d1b2d366ba42cf0dd1 Mon Sep 17 00:00:00 2001 From: Pascal Schumacher Date: Mon, 24 Jun 2019 22:07:13 +0200 Subject: [PATCH 197/348] Update Mockito version to 2.28.2 (fixes #57). --- pom.xml | 3 ++- .../lambda/internal/iteration/CombinatorialIteratorTest.java | 2 +- .../lambda/internal/iteration/DroppingIteratorTest.java | 2 +- .../lambda/internal/iteration/GroupingIteratorTest.java | 2 +- .../internal/iteration/PredicatedDroppingIteratorTest.java | 2 +- .../lambda/internal/iteration/ReversingIteratorTest.java | 2 +- .../lambda/internal/iteration/RewindableIteratorTest.java | 2 +- .../lambda/internal/iteration/ZippingIteratorTest.java | 2 +- src/test/java/testsupport/matchers/ZeroInvocationsMatcher.java | 3 ++- 9 files changed, 11 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 31902087d..6837ce09a 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,8 @@ org.mockito - mockito-all + mockito-core + 2.28.2 com.jnape.palatable diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java index 639136dd7..71352becf 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java @@ -4,7 +4,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import java.util.Iterator; diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java index b13dc33d1..0abdb857e 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/DroppingIteratorTest.java @@ -4,7 +4,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import java.util.Iterator; diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java index 0288574d2..d4e1df3ab 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/GroupingIteratorTest.java @@ -4,7 +4,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import java.util.Iterator; diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java index bb3afa82f..7fb0613c3 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java @@ -5,7 +5,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java index 1fd9afce1..dd31b4bf7 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ReversingIteratorTest.java @@ -4,7 +4,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import java.util.Iterator; diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java index 532397934..33bda1ad4 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java @@ -4,7 +4,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java index 96e655db0..cc96157f2 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java @@ -5,7 +5,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import java.util.Iterator; diff --git a/src/test/java/testsupport/matchers/ZeroInvocationsMatcher.java b/src/test/java/testsupport/matchers/ZeroInvocationsMatcher.java index 3757eef2c..ea4884fdb 100644 --- a/src/test/java/testsupport/matchers/ZeroInvocationsMatcher.java +++ b/src/test/java/testsupport/matchers/ZeroInvocationsMatcher.java @@ -5,6 +5,7 @@ import org.hamcrest.Matcher; import org.mockito.exceptions.misusing.NotAMockException; import org.mockito.exceptions.verification.NoInteractionsWanted; +import org.mockito.internal.stubbing.InvocationContainerImpl; import org.mockito.internal.util.MockUtil; import org.mockito.invocation.Invocation; @@ -26,7 +27,7 @@ public boolean matches(Object item) { @Override public void describeMismatch(Object item, final Description description) { description.appendText("had these: "); - for (Invocation invocation : new MockUtil().getMockHandler(item).getInvocationContainer().getInvocations()) + for (Invocation invocation : ((InvocationContainerImpl) MockUtil.getMockHandler(item).getInvocationContainer()).getInvocations()) description.appendText(invocation.toString()); } From 384a9d5e5473b9a797b9d73faa04b9692ecb0742 Mon Sep 17 00:00:00 2001 From: Pascal Schumacher Date: Mon, 24 Jun 2019 22:11:45 +0200 Subject: [PATCH 198/348] Fix unnecessary stubbing errors. --- .../lambda/internal/iteration/CombinatorialIteratorTest.java | 1 - .../lambda/internal/iteration/ZippingIteratorTest.java | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java index 71352becf..9e52df9b3 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/CombinatorialIteratorTest.java @@ -46,7 +46,6 @@ public void doesNotHaveNextIfMoreAsButNoBs() { @Test public void doesNotHaveNextIfNoAsButMoreBs() { when(as.hasNext()).thenReturn(false); - when(bs.hasNext()).thenReturn(true); assertThat(combinatorialIterator.hasNext(), is(false)); } diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java index cc96157f2..9fb639a6a 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/ZippingIteratorTest.java @@ -38,7 +38,6 @@ public void hasNextIfMoreAsAndMoreBs() { @Test public void doesNotHaveNextIfAsDoesNotHaveNext() { when(as.hasNext()).thenReturn(false); - when(bs.hasNext()).thenReturn(true); assertThat(zippingIterator.hasNext(), is(false)); } @@ -51,9 +50,6 @@ public void doesNotHaveNextIfBsDoesNotHaveNext() { @Test public void zipsNextElementFromAsAndBs() { - when(as.hasNext()).thenReturn(true); - when(bs.hasNext()).thenReturn(true); - when(as.next()).thenReturn(1); when(bs.next()).thenReturn(2); From 0b559dd47b709a244d49af1848d339e77da9a133 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 24 Jun 2019 18:57:52 -0500 Subject: [PATCH 199/348] Clearing last of the Mockito reflection warnings --- .../functions/builtin/fn1/SizeTest.java | 21 ++++++++++++------- .../matchers/ZeroInvocationsMatcher.java | 5 ++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java index a0039dc3e..1a127054f 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java @@ -4,13 +4,12 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Iterator; import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; public class SizeTest { @@ -23,12 +22,18 @@ public void countsElementsInIterable() { @Test @SuppressWarnings("serial") public void optimizesForCollections() { - Collection collection = spy(new ArrayList() {{ - add(1); - add(2); - add(3); - }}); - when(collection.iterator()).thenThrow(new IllegalStateException("should not be using the iterator")); + Collection collection = new ArrayList() { + @Override + public Iterator iterator() { + throw new IllegalStateException("should not be using the iterator"); + } + + { + add(1); + add(2); + add(3); + } + }; assertEquals((Long) 3L, size(collection)); } } \ No newline at end of file diff --git a/src/test/java/testsupport/matchers/ZeroInvocationsMatcher.java b/src/test/java/testsupport/matchers/ZeroInvocationsMatcher.java index ea4884fdb..9c360867c 100644 --- a/src/test/java/testsupport/matchers/ZeroInvocationsMatcher.java +++ b/src/test/java/testsupport/matchers/ZeroInvocationsMatcher.java @@ -5,11 +5,10 @@ import org.hamcrest.Matcher; import org.mockito.exceptions.misusing.NotAMockException; import org.mockito.exceptions.verification.NoInteractionsWanted; -import org.mockito.internal.stubbing.InvocationContainerImpl; -import org.mockito.internal.util.MockUtil; import org.mockito.invocation.Invocation; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.internal.util.MockUtil.getInvocationContainer; public class ZeroInvocationsMatcher extends BaseMatcher { @Override @@ -27,7 +26,7 @@ public boolean matches(Object item) { @Override public void describeMismatch(Object item, final Description description) { description.appendText("had these: "); - for (Invocation invocation : ((InvocationContainerImpl) MockUtil.getMockHandler(item).getInvocationContainer()).getInvocations()) + for (Invocation invocation : getInvocationContainer(item).getInvocations()) description.appendText(invocation.toString()); } From 076ea6e4041f0cd2e467a071db62f67b2cefb55a Mon Sep 17 00:00:00 2001 From: Pascal Schumacher Date: Mon, 24 Jun 2019 22:50:09 +0200 Subject: [PATCH 200/348] Update Hamcrest to version 2.1. --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 6837ce09a..f83f19a15 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ 1.2 3.3 - 1.3 + 2.1 3.1.1 @@ -66,8 +66,8 @@ org.hamcrest - hamcrest-all - ${hamcrest-all.version} + hamcrest + ${hamcrest.version} test From efa0d763ef87c7152698d1a979b8fd8568f8d83d Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 25 Jun 2019 17:27:45 -0500 Subject: [PATCH 201/348] Updating travis, again --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a8ca1b4c2..39074daea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,4 @@ dist: trusty language: java jdk: - oraclejdk8 - - oraclejdk11 + - openjdk11 From 1e1c766a2a463886a70174586087bc718b8b2e0c Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 30 Jun 2019 15:13:12 -0500 Subject: [PATCH 202/348] Adding more IO primitives, monitorSync/interruptible/fuse/pin --- CHANGELOG.md | 4 + .../com/jnape/palatable/lambda/io/IO.java | 75 ++++++++++++++++++- .../com/jnape/palatable/lambda/io/IOTest.java | 73 ++++++++++++++++++ 3 files changed, 150 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49ec83bbb..556aaaae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Prism#fromPartial` public interfaces - `ReaderT`, the transformer for the reader monad - `Until`, for repeatedly executing an `IO` until its result matches a predicate +- `IO#interruptible`, for wrapping an `IO` in a thread interruption check +- `IO#monitorSync`, for wrapping an `IO` in a `synchronized` block on a given lock object +- `IO#pin`, for pinning an `IO` to an `Executor` without yet executing it +- `IO#fuse`, for fusing the fork opportunities of a given `IO` into a single linearized `IO` ## [4.0.0] - 2019-05-20 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 9bfb586e6..ff0ab2fa1 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -18,11 +18,13 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; +import static com.jnape.palatable.lambda.adt.choice.Choice2.b; import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.monad.Monad.join; +import static java.lang.Thread.interrupted; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.CompletableFuture.supplyAsync; import static java.util.concurrent.ForkJoinPool.commonPool; @@ -138,7 +140,7 @@ public final IO fmap(Fn1 fn) { * {@inheritDoc} */ @Override - public IO zip(Applicative, IO> appFn) { + public final IO zip(Applicative, IO> appFn) { return new Compose<>(this, a((IO>) appFn)); } @@ -172,7 +174,7 @@ public final IO discardR(Applicative> appB) { @Override public final IO flatMap(Fn1>> f) { @SuppressWarnings({"unchecked", "RedundantCast"}) - Choice2, Fn1>> composition = Choice2.b((Fn1>) (Object) f); + Choice2, Fn1>> composition = b((Fn1>) (Object) f); return new Compose<>(this, composition); } @@ -187,6 +189,75 @@ public static IO throwing(Throwable t) { return io(() -> {throw t;}); } + /** + * Wrap the given {@link IO} in an {@link IO} that first checks if the {@link Thread#currentThread() thread} the + * {@link IO} runs on is {@link Thread#interrupted() interrupted}. If it is, an {@link InterruptedException} is + * thrown; otherwise the given {@link IO} is executed as usual. Note that for {@link IO}s supporting parallelism, + * the thread that is checked for interruption may not necessarily be the same thread that the {@link IO} ultimately + * runs on. + * + * @param io the {@link IO} to wrap + * @param the {@link IO} result type + * @return an {@link IO} that first checks for {@link Thread#interrupted() thread interrupts} + */ + public static IO interruptible(IO io) { + return join(io(() -> { + if (interrupted()) + throw new InterruptedException(); + return io; + })); + } + + /** + * Synchronize the given + * {@link IO} using the provided lock object. Note that to ensure that the entirety of the {@link IO}'s computation + * actually runs inside the synchronized region, the {@link IO} is executed + * {@link IO#unsafePerformIO() synchronously} inside the synchronized block regardless of the caller's chosen + * execution strategy. + * + * @param lock the lock object + * @param io the {@link IO} + * @param the {@link IO} result type + * @return the synchronized {@link IO} + */ + public static IO monitorSync(Object lock, IO io) { + return io(() -> { + synchronized (lock) { + return io.unsafePerformIO(); + } + }); + } + + /** + * Fuse all fork opportunities of a given {@link IO} such that, unless it is {@link IO#pin(IO, Executor) pinned} + * (or is originally {@link IO#externallyManaged(Fn0) externally managed}), no parallelism will be used when + * running it, regardless of what semantics are used when it is executed. + * + * @param io the {@link IO} + * @param the {@link IO} result type + * @return the fused {@link IO} + * @see IO#pin(IO, Executor) + */ + public static IO fuse(IO io) { + return io(io::unsafePerformIO); + } + + /** + * Pin an {@link IO} to an {@link Executor} such that regardless of what future decisions are made, when it runs, it + * will run using whatever parallelism is supported by the {@link Executor}'s threading model. Note that if this + * {@link IO} has already been pinned (or is originally {@link IO#externallyManaged(Fn0) externally managed}), + * pinning to an additional {@link Executor} has no meaningful effect. + * + * @param io the {@link IO} + * @param executor the {@link Executor} + * @param the {@link IO} result type + * @return the {@link IO} pinned to the {@link Executor} + * @see IO#fuse(IO) + */ + public static IO pin(IO io, Executor executor) { + return IO.externallyManaged(() -> io.unsafePerformAsyncIO(executor)); + } + /** * Static factory method for creating an {@link IO} that just returns a when performed. * diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 3dc288ec0..5d9c4dffe 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -1,18 +1,23 @@ package com.jnape.palatable.lambda.io; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Sequence; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -24,24 +29,31 @@ import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; +import static com.jnape.palatable.lambda.functions.builtin.fn3.LiftA2.liftA2; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.io.IO.externallyManaged; import static com.jnape.palatable.lambda.io.IO.io; +import static java.lang.Thread.currentThread; +import static java.util.Arrays.asList; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.Executors.newFixedThreadPool; import static java.util.concurrent.ForkJoinPool.commonPool; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static testsupport.Constants.STACK_EXPLODING_NUMBER; @RunWith(Traits.class) public class IOTest { + public @Rule ExpectedException thrown = ExpectedException.none(); + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) public EquatableM, Integer> testSubject() { return new EquatableM<>(io(1), IO::unsafePerformIO); @@ -295,4 +307,65 @@ public void sequenceIsRepeatable() { assertEquals((Long) 3L, size(io.unsafePerformIO())); assertEquals((Long) 3L, size(io.unsafePerformIO())); } + + @Test(expected = InterruptedException.class) + public void interruptible() { + currentThread().interrupt(); + + IO io = IO.interruptible(IO.throwing(new AssertionError("expected to never be called"))); + io.unsafePerformIO(); + } + + @Test + public void monitorSync() throws InterruptedException { + Object lock = new Object(); + List accesses = new ArrayList<>(); + CountDownLatch oneStarted = new CountDownLatch(1); + CountDownLatch finishLine = new CountDownLatch(2); + + IO one = io(() -> { + accesses.add("one entered"); + oneStarted.countDown(); + Thread.sleep(10); + accesses.add("one exited"); + finishLine.countDown(); + }); + + IO two = io(() -> { + oneStarted.await(); + accesses.add("two entered"); + Thread.sleep(10); + accesses.add("two exited"); + finishLine.countDown(); + }); + + new Thread(IO.monitorSync(lock, one)::unsafePerformIO) {{ + start(); + }}; + + new Thread(IO.monitorSync(lock, two)::unsafePerformIO) {{ + start(); + }}; + + finishLine.await(500, MILLISECONDS); + assertEquals(asList("one entered", "one exited", "two entered", "two exited"), accesses); + } + + @Test + public void fuse() { + IO currentThreadIO = io(Thread::currentThread); + IO> threads = liftA2(HList::tuple, currentThreadIO, currentThreadIO); + Executor executor = Executors.newFixedThreadPool(2); + Boolean sameThread = IO.fuse(threads).unsafePerformAsyncIO(executor).join().into(eq()); + assertTrue("Expected both IOs to run on the same Thread, but they didn't.", sameThread); + } + + @Test + public void pin() { + Thread mainThread = currentThread(); + IO currentThreadIO = io(Thread::currentThread); + Executor executor = Executors.newFixedThreadPool(2); + Thread chosenThread = IO.pin(currentThreadIO, Runnable::run).unsafePerformAsyncIO(executor).join(); + assertEquals("Expected IO to run on the main Thread, but it didn't.", mainThread, chosenThread); + } } \ No newline at end of file From 581cea5a31c2366175a89fee51cab07b84058105 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 30 Jun 2019 15:30:03 -0500 Subject: [PATCH 203/348] Using CompletionStage#thenCombineAsync is more straightforward for zip --- .../com/jnape/palatable/lambda/io/IO.java | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index ff0ab2fa1..c182de3b9 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -1,7 +1,6 @@ package com.jnape.palatable.lambda.io; import com.jnape.palatable.lambda.adt.Either; -import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.functions.Fn0; @@ -16,6 +15,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; @@ -84,7 +84,7 @@ public final IO exceptionally(Fn1 recoveryFn) return new IO() { @Override public A unsafePerformIO() { - return Try.trying(IO.this::unsafePerformIO).recover(recoveryFn); + return trying(IO.this::unsafePerformIO).recover(recoveryFn); } @Override @@ -94,6 +94,30 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { }; } +// /** +// * Given a function from any {@link Throwable} to the result type A, if this {@link IO} successfully +// * yields a result, return it; otherwise, map the {@link Throwable} to the result type and return that. +// * +// * @param recoveryFn the recovery function +// * @return the guarded {@link IO} +// */ +// public final IO exceptionallyIO(Fn1> recoveryFn) { +// return new IO() { +// @Override +// public A unsafePerformIO() { +// return trying(IO.this::unsafePerformIO).recover(t -> recoveryFn.apply(t).unsafePerformIO()) +// } +// +// @Override +// public CompletableFuture unsafePerformAsyncIO(Executor executor) { +//// IO.this.unsafePerformAsyncIO(executor) +//// .thenCombine() +//// .exceptionally(t -> recoveryFn.apply(t).unsafePerformAsyncIO(executor)) +// } +// }; +// } + + /** * Return an {@link IO} that will run ensureIO strictly after running this {@link IO} regardless of * whether this {@link IO} terminates normally, analogous to a finally block. @@ -378,8 +402,10 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { Lazy> head = f.apply(compose.source); return compose.composition .match(zip -> head.flatMap(futureX -> f.apply(zip) - .fmap(futureF -> futureF.thenCompose(f2 -> futureX - .thenApply(((Fn1) f2).toFunction())))), + .fmap(futureF -> futureF.thenCombineAsync( + futureX, + (f2, x) -> ((Fn1) f2).apply(x), + executor))), flatMap -> head.fmap(futureX -> futureX .thenComposeAsync(x -> f.apply(flatMap.apply(x)).value(), executor))); From cfa631797adfa115f365bb5bf9d8d59cc003a8fe Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 30 Jun 2019 16:21:59 -0500 Subject: [PATCH 204/348] IO#exceptionallyIO --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/io/IO.java | 59 +++++++++++-------- .../com/jnape/palatable/lambda/io/IOTest.java | 38 +++++++++--- 3 files changed, 63 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 556aaaae8..b22b84391 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `IO#monitorSync`, for wrapping an `IO` in a `synchronized` block on a given lock object - `IO#pin`, for pinning an `IO` to an `Executor` without yet executing it - `IO#fuse`, for fusing the fork opportunities of a given `IO` into a single linearized `IO` +- `IO#exceptionallyIO`, like `exceptionally` but recover inside another `IO` ## [4.0.0] - 2019-05-20 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index c182de3b9..6e2f79406 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.io; import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.functions.Fn0; @@ -15,6 +16,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import static com.jnape.palatable.lambda.adt.Try.failure; import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; @@ -81,43 +83,48 @@ public final CompletableFuture unsafePerformAsyncIO() { * @return the guarded {@link IO} */ public final IO exceptionally(Fn1 recoveryFn) { + return exceptionallyIO(t -> io(recoveryFn.apply(t))); + } + + /** + * Like {@link IO#exceptionally(Fn1) exceptionally}, but recover the {@link Throwable} via another {@link IO} + * operation. If both {@link IO IOs} throw, the "cleanup" {@link IO IO's} {@link Throwable} is + * {@link Throwable#addSuppressed(Throwable) suppressed} by this {@link IO IO's} {@link Throwable}. + * + * @param recoveryFn the recovery function + * @return the guarded {@link IO} + */ + public final IO exceptionallyIO(Fn1> recoveryFn) { return new IO() { @Override public A unsafePerformIO() { - return trying(IO.this::unsafePerformIO).recover(recoveryFn); + return trying(IO.this::unsafePerformIO) + .recover(t -> trying(recoveryFn.apply(t)::unsafePerformIO) + .fmap(Try::success) + .recover(t2 -> { + t.addSuppressed(t2); + return failure(t); + }) + .orThrow()); } @Override public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return IO.this.unsafePerformAsyncIO(executor).exceptionally(recoveryFn::apply); + return IO.this.unsafePerformAsyncIO(executor) + .thenApply(CompletableFuture::completedFuture) + .exceptionally(t -> recoveryFn.apply(t).unsafePerformAsyncIO(executor) + .thenApply(CompletableFuture::completedFuture) + .exceptionally(t2 -> { + t.addSuppressed(t2); + return new CompletableFuture() {{ + completeExceptionally(t); + }}; + }).thenCompose(f -> f)) + .thenCompose(f -> f); } }; } -// /** -// * Given a function from any {@link Throwable} to the result type A, if this {@link IO} successfully -// * yields a result, return it; otherwise, map the {@link Throwable} to the result type and return that. -// * -// * @param recoveryFn the recovery function -// * @return the guarded {@link IO} -// */ -// public final IO exceptionallyIO(Fn1> recoveryFn) { -// return new IO() { -// @Override -// public A unsafePerformIO() { -// return trying(IO.this::unsafePerformIO).recover(t -> recoveryFn.apply(t).unsafePerformIO()) -// } -// -// @Override -// public CompletableFuture unsafePerformAsyncIO(Executor executor) { -//// IO.this.unsafePerformAsyncIO(executor) -//// .thenCombine() -//// .exceptionally(t -> recoveryFn.apply(t).unsafePerformAsyncIO(executor)) -// } -// }; -// } - - /** * Return an {@link IO} that will run ensureIO strictly after running this {@link IO} regardless of * whether this {@link IO} terminates normally, analogous to a finally block. diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 5d9c4dffe..0958cb3a3 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -120,9 +120,12 @@ public void delegatesToExternallyManagedFuture() { } @Test - public void exceptionallyRecoversThrowableToResult() { - IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); + public void exceptionally() { + Executor executor = newFixedThreadPool(2); + IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); assertEquals("foo", io.exceptionally(Throwable::getMessage).unsafePerformIO()); + assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO().join()); + assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO(executor).join()); IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ completeExceptionally(new UnsupportedOperationException("foo")); @@ -131,19 +134,36 @@ public void exceptionallyRecoversThrowableToResult() { } @Test - public void exceptionallyRescuesFutures() { - ExecutorService executor = newFixedThreadPool(2); - - IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); - assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO().join()); - assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO(executor).join()); + public void exceptionallyIO() { + Executor executor = newFixedThreadPool(2); + IO io = IO.throwing(new UnsupportedOperationException("foo")); + assertEquals("foo", io.exceptionallyIO(t -> io(t::getMessage)).unsafePerformIO()); + assertEquals("foo", + io.exceptionallyIO(e -> io(() -> e.getCause().getMessage())).unsafePerformAsyncIO().join()); + assertEquals("foo", + io.exceptionallyIO(e -> io(() -> e.getCause().getMessage())) + .unsafePerformAsyncIO(executor).join()); IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ completeExceptionally(new UnsupportedOperationException("foo")); - }}).exceptionally(e -> e.getCause().getMessage()); + }}).exceptionallyIO(e -> io(() -> e.getCause().getMessage())); assertEquals("foo", externallyManaged.unsafePerformIO()); } + @Test + public void exceptionallyIOSuppressesSecondaryThrowable() { + Throwable foo = new UnsupportedOperationException("foo"); + Throwable bar = new UnsupportedOperationException("bar"); + + try { + IO.throwing(foo).exceptionallyIO(t -> IO.throwing(bar)).unsafePerformIO(); + fail("Expected exception to have been thrown, but wasn't."); + } catch (UnsupportedOperationException expected) { + assertEquals(expected, foo); + assertArrayEquals(new Throwable[]{bar}, expected.getSuppressed()); + } + } + @Test public void safe() { assertEquals(right(1), io(() -> 1).safe().unsafePerformIO()); From b5fb01d32021512bae2ab2b8dafc6ea1fd11d24e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 30 Jun 2019 16:42:48 -0500 Subject: [PATCH 205/348] Call this a "type checker" with a straight face, I dare you --- .../com/jnape/palatable/lambda/io/IO.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 6e2f79406..74ce4fae1 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -98,14 +98,17 @@ public final IO exceptionallyIO(Fn1> recov return new IO() { @Override public A unsafePerformIO() { - return trying(IO.this::unsafePerformIO) - .recover(t -> trying(recoveryFn.apply(t)::unsafePerformIO) - .fmap(Try::success) - .recover(t2 -> { - t.addSuppressed(t2); - return failure(t); - }) - .orThrow()); + return trying(fn0(IO.this::unsafePerformIO)) + .recover(t -> { + IO recoveryIO = recoveryFn.apply(t); + return trying(fn0(recoveryIO::unsafePerformIO)) + .fmap(Try::success) + .recover(t2 -> { + t.addSuppressed(t2); + return failure(t); + }) + .orThrow(); + }); } @Override From b7e12cf8fa7843a49a208d0fb0ee6e6af968d0e1 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 4 Jul 2019 18:28:49 -0500 Subject: [PATCH 206/348] Moving to main classpath --- .../com/jnape/palatable/lambda/functions/builtin/fn2/Until.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{test => main}/java/com/jnape/palatable/lambda/functions/builtin/fn2/Until.java (100%) diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Until.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Until.java similarity index 100% rename from src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Until.java rename to src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Until.java From 02d0d7da5d8d75a2af87dbd126b95b19d9f682ea Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 4 Jul 2019 18:34:23 -0500 Subject: [PATCH 207/348] Fixing warning on old versions of jdk 8 --- src/main/java/com/jnape/palatable/lambda/io/IO.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 74ce4fae1..920c77b36 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -9,7 +9,6 @@ import com.jnape.palatable.lambda.functions.builtin.fn2.LazyRec; import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -183,7 +182,7 @@ public final IO zip(Applicative, IO> appFn */ @Override public final Lazy> lazyZip(Lazy, IO>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).>fmap(Functor::coerce).coerce(); + return Monad.super.lazyZip(lazyAppFn).>fmap(Monad>::coerce).coerce(); } /** From a5d81eea1ece5635f4558b2a062cf6af232acdc7 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 11 Jul 2019 01:26:56 -0500 Subject: [PATCH 208/348] MonadError, monads that can be thrown to and caught from - Either - IO - Try - Maybe --- CHANGELOG.md | 1 + pom.xml | 9 +- .../jnape/palatable/lambda/adt/Either.java | 27 ++++- .../com/jnape/palatable/lambda/adt/Maybe.java | 27 ++++- .../com/jnape/palatable/lambda/adt/Try.java | 30 ++++- .../com/jnape/palatable/lambda/io/IO.java | 114 +++++++++--------- .../palatable/lambda/monad/MonadError.java | 90 ++++++++++++++ .../palatable/lambda/adt/EitherTest.java | 6 + .../jnape/palatable/lambda/adt/MaybeTest.java | 6 + .../jnape/palatable/lambda/adt/TheseTest.java | 1 + .../jnape/palatable/lambda/adt/TryTest.java | 9 ++ .../com/jnape/palatable/lambda/io/IOTest.java | 39 +++--- src/test/java/testsupport/EquatableM.java | 8 ++ .../assertion/MonadErrorAssert.java | 49 ++++++++ .../java/testsupport/matchers/IOMatcher.java | 49 ++++++++ 15 files changed, 374 insertions(+), 91 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/MonadError.java create mode 100644 src/test/java/testsupport/assertion/MonadErrorAssert.java create mode 100644 src/test/java/testsupport/matchers/IOMatcher.java diff --git a/CHANGELOG.md b/CHANGELOG.md index b22b84391..6877c602e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `IO#pin`, for pinning an `IO` to an `Executor` without yet executing it - `IO#fuse`, for fusing the fork opportunities of a given `IO` into a single linearized `IO` - `IO#exceptionallyIO`, like `exceptionally` but recover inside another `IO` +- `MonadError`, monads that can be thrown to and caught from ## [4.0.0] - 2019-05-20 ### Changed diff --git a/pom.xml b/pom.xml index f83f19a15..e4cb1a89f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -60,6 +61,12 @@ + + io.jaegertracing + jaeger-client + 0.35.5 + test + junit junit 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 29e421570..be7f01111 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -13,6 +13,7 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadError; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; @@ -32,7 +33,7 @@ */ public abstract class Either implements CoProduct2>, - Monad>, + MonadError>, Traversable>, Bifunctor> { @@ -206,7 +207,7 @@ public Choice3 diverge() { */ @Override public final Either fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadError.super.fmap(fn).coerce(); } /** @@ -247,7 +248,7 @@ public final Either pure(R2 r2) { */ @Override public final Either zip(Applicative, Either> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadError.super.zip(appFn).coerce(); } /** @@ -265,7 +266,7 @@ public Lazy> lazyZip( */ @Override public final Either discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadError.super.discardL(appB).coerce(); } /** @@ -273,7 +274,23 @@ public final Either discardL(Applicative> appB) { */ @Override public final Either discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadError.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Either throwError(L l) { + return left(l); + } + + /** + * {@inheritDoc} + */ + @Override + public Either catchError(Fn1>> recoveryFn) { + return match(recoveryFn.fmap(Monad::coerce), Either::right); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index 4cc726673..6b92e13ca 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -13,6 +13,7 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadError; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; @@ -34,7 +35,7 @@ */ public abstract class Maybe implements CoProduct2>, - Monad>, + MonadError>, Traversable> { private Maybe() { @@ -86,6 +87,22 @@ public final Maybe filter(Fn1 predicate) { return flatMap(a -> predicate.apply(a) ? just(a) : nothing()); } + /** + * {@inheritDoc} + */ + @Override + public Maybe throwError(Unit unit) { + return nothing(); + } + + /** + * {@inheritDoc} + */ + @Override + public Maybe catchError(Fn1>> recoveryFn) { + return match(recoveryFn, Maybe::just).coerce(); + } + /** * If this value is absent, return the value supplied by lSupplier wrapped in Either.left. * Otherwise, wrap the value in Either.right and return it. @@ -127,7 +144,7 @@ public final Maybe pure(B b) { */ @Override public final Maybe fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadError.super.fmap(fn).coerce(); } /** @@ -135,7 +152,7 @@ public final Maybe fmap(Fn1 fn) { */ @Override public final Maybe zip(Applicative, Maybe> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadError.super.zip(appFn).coerce(); } /** @@ -156,7 +173,7 @@ public Lazy> lazyZip(Lazy Maybe discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadError.super.discardL(appB).coerce(); } /** @@ -164,7 +181,7 @@ public final Maybe discardL(Applicative> appB) { */ @Override public final Maybe discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadError.super.discardR(appB).coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index bdc2ec040..511dd26e0 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -8,6 +8,7 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadError; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; @@ -27,7 +28,10 @@ * @param the possibly successful expression result * @see Either */ -public abstract class Try implements Monad>, Traversable>, CoProduct2> { +public abstract class Try implements + MonadError>, + Traversable>, + CoProduct2> { private Try() { } @@ -162,12 +166,28 @@ public final Either toEither(Fn1 fn) { return match(fn.fmap(Either::left), Either::right); } + /** + * {@inheritDoc} + */ + @Override + public Try throwError(Throwable throwable) { + return failure(throwable); + } + + /** + * {@inheritDoc} + */ + @Override + public Try catchError(Fn1>> recoveryFn) { + return match(t -> recoveryFn.apply(t).coerce(), Try::success); + } + /** * {@inheritDoc} */ @Override public Try fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadError.super.fmap(fn).coerce(); } /** @@ -191,7 +211,7 @@ public Try pure(B b) { */ @Override public Try zip(Applicative, Try> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadError.super.zip(appFn).coerce(); } /** @@ -208,7 +228,7 @@ public Lazy> lazyZip(Lazy Try discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadError.super.discardL(appB).coerce(); } /** @@ -216,7 +236,7 @@ public Try discardL(Applicative> appB) { */ @Override public Try discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadError.super.discardR(appB).coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 920c77b36..3ac81450a 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -11,10 +11,12 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadError; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Try.failure; import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.adt.Unit.UNIT; @@ -37,7 +39,7 @@ * * @param the result type */ -public abstract class IO implements Monad> { +public abstract class IO implements Monad>, MonadError> { private IO() { } @@ -80,51 +82,11 @@ public final CompletableFuture unsafePerformAsyncIO() { * * @param recoveryFn the recovery function * @return the guarded {@link IO} + * @deprecated in favor of canonical {@link IO#catchError(Fn1)} */ + @Deprecated public final IO exceptionally(Fn1 recoveryFn) { - return exceptionallyIO(t -> io(recoveryFn.apply(t))); - } - - /** - * Like {@link IO#exceptionally(Fn1) exceptionally}, but recover the {@link Throwable} via another {@link IO} - * operation. If both {@link IO IOs} throw, the "cleanup" {@link IO IO's} {@link Throwable} is - * {@link Throwable#addSuppressed(Throwable) suppressed} by this {@link IO IO's} {@link Throwable}. - * - * @param recoveryFn the recovery function - * @return the guarded {@link IO} - */ - public final IO exceptionallyIO(Fn1> recoveryFn) { - return new IO() { - @Override - public A unsafePerformIO() { - return trying(fn0(IO.this::unsafePerformIO)) - .recover(t -> { - IO recoveryIO = recoveryFn.apply(t); - return trying(fn0(recoveryIO::unsafePerformIO)) - .fmap(Try::success) - .recover(t2 -> { - t.addSuppressed(t2); - return failure(t); - }) - .orThrow(); - }); - } - - @Override - public CompletableFuture unsafePerformAsyncIO(Executor executor) { - return IO.this.unsafePerformAsyncIO(executor) - .thenApply(CompletableFuture::completedFuture) - .exceptionally(t -> recoveryFn.apply(t).unsafePerformAsyncIO(executor) - .thenApply(CompletableFuture::completedFuture) - .exceptionally(t2 -> { - t.addSuppressed(t2); - return new CompletableFuture() {{ - completeExceptionally(t); - }}; - }).thenCompose(f -> f)) - .thenCompose(f -> f); - } - }; + return catchError(t -> io(recoveryFn.apply(t))); } /** @@ -136,11 +98,12 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { */ public final IO ensuring(IO ensureIO) { return join(fmap(a -> ensureIO.fmap(constantly(a))) - .exceptionally(t -> join(ensureIO.>fmap(constantly(io(() -> {throw t;}))) - .exceptionally(t2 -> io(() -> { - t.addSuppressed(t2); - throw t; - }))))); + .catchError(t1 -> ensureIO + .fmap(constantly(IO.throwing(t1))) + .catchError(t2 -> io(io(() -> { + t1.addSuppressed(t2); + throw t1; + }))))); } /** @@ -150,7 +113,7 @@ public final IO ensuring(IO ensureIO) { * @return the safe {@link IO} */ public final IO> safe() { - return fmap(Either::right).exceptionally(Either::left); + return fmap(Either::right).catchError(t -> io(left(t))); } /** @@ -166,7 +129,7 @@ public final IO pure(B b) { */ @Override public final IO fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadError.super.fmap(fn).coerce(); } /** @@ -182,7 +145,7 @@ public final IO zip(Applicative, IO> appFn */ @Override public final Lazy> lazyZip(Lazy, IO>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).>fmap(Monad>::coerce).coerce(); + return MonadError.super.lazyZip(lazyAppFn).>fmap(Monad>::coerce).coerce(); } /** @@ -190,7 +153,7 @@ public final Lazy> lazyZip(Lazy IO discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadError.super.discardL(appB).coerce(); } /** @@ -198,7 +161,7 @@ public final IO discardL(Applicative> appB) { */ @Override public final IO discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadError.super.discardR(appB).coerce(); } /** @@ -211,6 +174,49 @@ public final IO flatMap(Fn1>> f) { return new Compose<>(this, composition); } + /** + * {@inheritDoc} + */ + @Override + public final IO throwError(Throwable throwable) { + return IO.throwing(throwable); + } + + /** + * {@inheritDoc} + */ + @Override + public final IO catchError(Fn1>> recoveryFn) { + return new IO() { + @Override + public A unsafePerformIO() { + return trying(fn0(IO.this::unsafePerformIO)) + .recover(t -> trying(fn0(recoveryFn.apply(t).>coerce()::unsafePerformIO)) + .fmap(Try::success) + .recover(t2 -> { + t.addSuppressed(t2); + return failure(t); + }) + .orThrow()); + } + + @Override + public CompletableFuture unsafePerformAsyncIO(Executor executor) { + return IO.this.unsafePerformAsyncIO(executor) + .thenApply(CompletableFuture::completedFuture) + .exceptionally(t -> recoveryFn.apply(t).>coerce().unsafePerformAsyncIO(executor) + .thenApply(CompletableFuture::completedFuture) + .exceptionally(t2 -> { + t.addSuppressed(t2); + return new CompletableFuture() {{ + completeExceptionally(t); + }}; + }).thenCompose(f -> f)) + .thenCompose(f -> f); + } + }; + } + /** * Produce an {@link IO} that throws the given {@link Throwable} when executed. * diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java new file mode 100644 index 000000000..ad423ef75 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java @@ -0,0 +1,90 @@ +package com.jnape.palatable.lambda.monad; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.io.IO; + +/** + * An interface for {@link Monad monads} that can be interrupted with some type of error. The type of error is fully + * dictated by the instance of {@link MonadError} and is not necessarily analogous to Java {@link Exception exceptions} + * or even {@link Throwable}. For instance, {@link IO} can be thrown any {@link Throwable}, where as {@link Either} can + * only be "thrown" a value of its {@link Either#left(Object) left} type. + * + * @param the error type + * @param the {@link Monad} witness + * @param the carrier + */ +public interface MonadError> extends Monad { + + /** + * Throw an error value of type E into the {@link Monad monad}. + * + * @param e the error type + * @return the {@link Monad monad} + */ + MonadError throwError(E e); + + /** + * Catch any {@link MonadError#throwError(Object) thrown} errors inside the {@link Monad} and resume normal + * operations. + * + * @param recoveryFn the catch function + * @return the recovered {@link Monad} + */ + MonadError catchError(Fn1> recoveryFn); + + /** + * {@inheritDoc} + */ + @Override + MonadError flatMap(Fn1> f); + + /** + * {@inheritDoc} + */ + @Override + MonadError pure(B b); + + /** + * {@inheritDoc} + */ + @Override + default MonadError fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadError zip(Applicative, M> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Lazy> lazyZip( + Lazy, M>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadError discardL(Applicative appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadError discardR(Applicative appB) { + return Monad.super.discardR(appB).coerce(); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java index 37371ead6..8de5be33e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java @@ -29,6 +29,7 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static testsupport.assertion.MonadErrorAssert.assertLaws; @RunWith(Traits.class) public class EitherTest { @@ -41,6 +42,11 @@ public Subjects> testSubjects() { return subjects(left("foo"), right(1)); } + @Test + public void monadError() { + assertLaws(subjects(left("a"), right(1)), "bar", e -> right(e.length())); + } + @Test public void recoverLiftsLeftAndFlattensRight() { Either left = left("foo"); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java index 0548e74f4..ba02cadc7 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java @@ -28,6 +28,7 @@ import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; +import static testsupport.assertion.MonadErrorAssert.assertLaws; @RunWith(Traits.class) public class MaybeTest { @@ -37,6 +38,11 @@ public Subjects> testSubject() { return subjects(Maybe.nothing(), just(1)); } + @Test + public void monadError() { + assertLaws(subjects(nothing(), just(1)), UNIT, constantly(just(2))); + } + @Test(expected = NullPointerException.class) public void justMustBeNonNull() { just(null); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java index c4484c1a3..795054a87 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java @@ -17,6 +17,7 @@ import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; +import static testsupport.assertion.MonadErrorAssert.assertLaws; @RunWith(Traits.class) public class TheseTest { diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index ee6ad0dd7..92c0f7c19 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -37,6 +37,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static testsupport.assertion.MonadErrorAssert.assertLaws; import static testsupport.matchers.LeftMatcher.isLeftThat; @RunWith(Traits.class) @@ -49,6 +50,14 @@ public Subjects> testSubject() { return subjects(failure(new IllegalStateException()), success(1)); } + @Test + public void monadError() { + assertLaws(subjects(failure(new IllegalStateException("a")), + success(1)), + new IOException("bar"), + t -> success(t.getMessage().length())); + } + @Test public void catchingWithGenericPredicate() { Try caught = Try.failure(new RuntimeException()) diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 0958cb3a3..f19c4b554 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -16,6 +16,7 @@ import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -37,6 +38,7 @@ import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.io.IO.externallyManaged; import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.lang.Thread.currentThread; import static java.util.Arrays.asList; import static java.util.concurrent.CompletableFuture.completedFuture; @@ -48,6 +50,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static testsupport.Constants.STACK_EXPLODING_NUMBER; +import static testsupport.assertion.MonadErrorAssert.assertLawsEq; @RunWith(Traits.class) public class IOTest { @@ -59,6 +62,14 @@ public EquatableM, Integer> testSubject() { return new EquatableM<>(io(1), IO::unsafePerformIO); } + @Test + public void monadError() { + assertLawsEq(subjects(new EquatableM<>(IO.throwing(new IllegalStateException("a")), IO::unsafePerformIO), + new EquatableM<>(io(1), IO::unsafePerformIO)), + new IOException("bar"), + e -> io(e.getMessage().length())); + } + @Test public void staticFactoryMethods() { assertEquals((Integer) 1, io(1).unsafePerformIO()); @@ -120,43 +131,29 @@ public void delegatesToExternallyManagedFuture() { } @Test - public void exceptionally() { - Executor executor = newFixedThreadPool(2); - IO io = io(() -> { throw new UnsupportedOperationException("foo"); }); - assertEquals("foo", io.exceptionally(Throwable::getMessage).unsafePerformIO()); - assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO().join()); - assertEquals("foo", io.exceptionally(e -> e.getCause().getMessage()).unsafePerformAsyncIO(executor).join()); - - IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ - completeExceptionally(new UnsupportedOperationException("foo")); - }}).exceptionally(e -> e.getCause().getMessage()); - assertEquals("foo", externallyManaged.unsafePerformIO()); - } - - @Test - public void exceptionallyIO() { + public void catchError() { Executor executor = newFixedThreadPool(2); IO io = IO.throwing(new UnsupportedOperationException("foo")); - assertEquals("foo", io.exceptionallyIO(t -> io(t::getMessage)).unsafePerformIO()); + assertEquals("foo", io.catchError(t -> io(t::getMessage)).unsafePerformIO()); assertEquals("foo", - io.exceptionallyIO(e -> io(() -> e.getCause().getMessage())).unsafePerformAsyncIO().join()); + io.catchError(e -> io(() -> e.getCause().getMessage())).unsafePerformAsyncIO().join()); assertEquals("foo", - io.exceptionallyIO(e -> io(() -> e.getCause().getMessage())) + io.catchError(e -> io(() -> e.getCause().getMessage())) .unsafePerformAsyncIO(executor).join()); IO externallyManaged = externallyManaged(() -> new CompletableFuture() {{ completeExceptionally(new UnsupportedOperationException("foo")); - }}).exceptionallyIO(e -> io(() -> e.getCause().getMessage())); + }}).catchError(e -> io(() -> e.getCause().getMessage())); assertEquals("foo", externallyManaged.unsafePerformIO()); } @Test - public void exceptionallyIOSuppressesSecondaryThrowable() { + public void catchErrorSuppressesSecondaryThrowable() { Throwable foo = new UnsupportedOperationException("foo"); Throwable bar = new UnsupportedOperationException("bar"); try { - IO.throwing(foo).exceptionallyIO(t -> IO.throwing(bar)).unsafePerformIO(); + IO.throwing(foo).catchError(t -> IO.throwing(bar)).unsafePerformIO(); fail("Expected exception to have been thrown, but wasn't."); } catch (UnsupportedOperationException expected) { assertEquals(expected, foo); diff --git a/src/test/java/testsupport/EquatableM.java b/src/test/java/testsupport/EquatableM.java index a046e3fa6..faf561cd3 100644 --- a/src/test/java/testsupport/EquatableM.java +++ b/src/test/java/testsupport/EquatableM.java @@ -16,6 +16,14 @@ public EquatableM(Monad ma, Fn1 equatable) { this.equatable = equatable; } + public EquatableM with(Fn1, ? extends Monad> fn) { + return new EquatableM<>(fn.apply(ma), equatable); + } + + public EquatableM swap(Monad mb) { + return new EquatableM<>(mb, equatable); + } + @Override public EquatableM flatMap(Fn1>> f) { return new EquatableM<>(ma.flatMap(f.fmap(x -> x.>coerce().ma)), equatable); diff --git a/src/test/java/testsupport/assertion/MonadErrorAssert.java b/src/test/java/testsupport/assertion/MonadErrorAssert.java new file mode 100644 index 000000000..399be85fb --- /dev/null +++ b/src/test/java/testsupport/assertion/MonadErrorAssert.java @@ -0,0 +1,49 @@ +package testsupport.assertion; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monad.MonadError; +import com.jnape.palatable.traitor.framework.Subjects; +import testsupport.EquatableM; + +public final class MonadErrorAssert { + + private MonadErrorAssert() { + } + + public static > void assertLaws( + Subjects> subjects, + E e, + Fn1> recovery) { + + subjects.forEach(subject -> throwCatch(subject, e, recovery) + .peek(failures -> IO.throwing(new AssertionError("MonadError law failures\n\n" + failures)))); + } + + public static > void assertLawsEq( + Subjects> subjects, + E e, + Fn1> recovery) { + subjects.forEach(subject -> throwCatch(subject, e, recovery) + .peek(failures -> IO.throwing(new AssertionError("MonadError law failures\n\n" + failures)))); + } + + private static > Maybe throwCatch( + MonadError monadError, + E e, + Fn1> recovery) { + return throwCatch(new EquatableM<>(monadError, x -> x), e, recovery); + } + + private static > Maybe throwCatch( + EquatableM equatable, + E e, + Fn1> recovery) { + EquatableM eq = equatable.with(ma -> ma.>coerce().throwError(e).catchError(recovery)); + return eq.equals(eq.swap(recovery.apply(e))) + ? Maybe.nothing() + : Maybe.just("ThrowCatch failed: " + equatable + ".throwError(" + e + ")" + + ".catchError(recoveryFn) /= recovery.apply(" + e + ")"); + } +} diff --git a/src/test/java/testsupport/matchers/IOMatcher.java b/src/test/java/testsupport/matchers/IOMatcher.java new file mode 100644 index 000000000..5785af090 --- /dev/null +++ b/src/test/java/testsupport/matchers/IOMatcher.java @@ -0,0 +1,49 @@ +package testsupport.matchers; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.io.IO; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import java.util.concurrent.atomic.AtomicReference; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static org.hamcrest.Matchers.anything; + +public final class IOMatcher extends TypeSafeMatcher> { + + private final Either, Matcher> matcher; + private final AtomicReference> resultRef; + + private IOMatcher(Either, Matcher> matcher) { + this.matcher = matcher; + resultRef = new AtomicReference<>(); + } + + @Override + protected boolean matchesSafely(IO io) { + Either res = io.safe().unsafePerformIO(); + resultRef.set(res); + return res.match(t -> matcher.match(tMatcher -> tMatcher.matches(t), aMatcher -> false), + a -> matcher.match(tMatcher -> false, aMatcher -> aMatcher.matches(a))); + } + + @Override + public void describeTo(Description description) { + throw new UnsupportedOperationException(); + } + + public static IOMatcher isIOThat(Matcher matcher) { + return new IOMatcher<>(right(matcher)); + } + + public static IOMatcher isIOThatCompletesNormally() { + return isIOThat(anything()); + } + + public static IOMatcher isIOThatThrows(Matcher throwableMatcher) { + return new IOMatcher<>(left(throwableMatcher)); + } +} From fdd8092b54f3f1385c846164027ce3c42992196c Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 24 Jul 2019 17:47:46 -0500 Subject: [PATCH 209/348] EquatableM delegates lazyZip to monad; loosening test timeout --- src/test/java/com/jnape/palatable/lambda/io/IOTest.java | 4 +++- src/test/java/testsupport/EquatableM.java | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index f19c4b554..c29f4caee 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -45,6 +45,7 @@ import static java.util.concurrent.Executors.newFixedThreadPool; import static java.util.concurrent.ForkJoinPool.commonPool; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -364,7 +365,8 @@ public void monitorSync() throws InterruptedException { start(); }}; - finishLine.await(500, MILLISECONDS); + if (!finishLine.await(1, SECONDS)) + fail("Expected threads to have completed by now"); assertEquals(asList("one entered", "one exited", "two entered", "two exited"), accesses); } diff --git a/src/test/java/testsupport/EquatableM.java b/src/test/java/testsupport/EquatableM.java index faf561cd3..a812df222 100644 --- a/src/test/java/testsupport/EquatableM.java +++ b/src/test/java/testsupport/EquatableM.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import java.util.Objects; @@ -44,6 +45,13 @@ public EquatableM zip(Applicative, Equatab return new EquatableM<>(ma.zip(appFn.>>coerce().ma), equatable); } + @Override + public Lazy> lazyZip( + Lazy, EquatableM>> lazyAppFn) { + return ma.lazyZip(lazyAppFn.fmap(eqF -> eqF.>>coerce().ma)) + .fmap(mb -> new EquatableM<>(mb, equatable)); + } + @Override public EquatableM discardL(Applicative> appB) { return new EquatableM<>(ma.discardL(appB.>coerce().ma), equatable); From 48d20a138c77ca1f6a389aede9225afd1fe91b0a Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 24 Jul 2019 17:49:04 -0500 Subject: [PATCH 210/348] housekeeping --- .../jnape/palatable/lambda/adt/TryTest.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index 92c0f7c19..c126b82f8 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -25,6 +25,7 @@ import static com.jnape.palatable.lambda.adt.Try.failure; import static com.jnape.palatable.lambda.adt.Try.success; import static com.jnape.palatable.lambda.adt.Try.trying; +import static com.jnape.palatable.lambda.adt.Try.withResources; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; @@ -173,7 +174,7 @@ public void tryingCatchesAnyThrowableThrownDuringEvaluation() { @Test public void withResourcesCleansUpAutoCloseableInSuccessCase() { AtomicBoolean closed = new AtomicBoolean(false); - assertEquals(success(1), Try.withResources(() -> () -> closed.set(true), resource -> success(1))); + assertEquals(success(1), withResources(() -> (AutoCloseable) () -> closed.set(true), resource -> success(1))); assertTrue(closed.get()); } @@ -181,30 +182,30 @@ public void withResourcesCleansUpAutoCloseableInSuccessCase() { public void withResourcesCleansUpAutoCloseableInFailureCase() { AtomicBoolean closed = new AtomicBoolean(false); RuntimeException exception = new RuntimeException(); - assertEquals(Try.failure(exception), Try.withResources(() -> () -> closed.set(true), - resource -> { throw exception; })); + assertEquals(Try.failure(exception), withResources(() -> (AutoCloseable) () -> closed.set(true), + resource -> { throw exception; })); assertTrue(closed.get()); } @Test public void withResourcesExposesResourceCreationFailure() { IOException ioException = new IOException(); - assertEquals(Try.failure(ioException), Try.withResources(() -> { throw ioException; }, resource -> success(1))); + assertEquals(Try.failure(ioException), withResources(() -> { throw ioException; }, resource -> success(1))); } @Test public void withResourcesExposesResourceCloseFailure() { IOException ioException = new IOException(); - assertEquals(Try.failure(ioException), Try.withResources(() -> () -> { throw ioException; }, - resource -> success(1))); + assertEquals(Try.failure(ioException), withResources(() -> (AutoCloseable) () -> { throw ioException; }, + resource -> success(1))); } @Test public void withResourcesPreservesSuppressedExceptionThrownDuringClose() { RuntimeException rootException = new RuntimeException(); IOException nestedIOException = new IOException(); - Try failure = Try.withResources(() -> () -> { throw nestedIOException; }, - resource -> { throw rootException; }); + Try failure = withResources(() -> (AutoCloseable) () -> { throw nestedIOException; }, + resource -> { throw rootException; }); Throwable thrown = failure.recover(id()); assertEquals(thrown, rootException); @@ -214,10 +215,10 @@ public void withResourcesPreservesSuppressedExceptionThrownDuringClose() { @Test public void cascadingWithResourcesClosesInInverseOrder() { List closeMessages = new ArrayList<>(); - assertEquals(success(1), Try.withResources(() -> (AutoCloseable) () -> closeMessages.add("close a"), - a -> () -> closeMessages.add("close b"), - b -> () -> closeMessages.add("close c"), - c -> success(1))); + assertEquals(success(1), withResources(() -> (AutoCloseable) () -> closeMessages.add("close a"), + a -> () -> closeMessages.add("close b"), + b -> () -> closeMessages.add("close c"), + c -> success(1))); assertEquals(asList("close c", "close b", "close a"), closeMessages); } From 55cc2d408d38672ed10bcce6bb54909703a4b920 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 24 Jul 2019 18:42:34 -0500 Subject: [PATCH 211/348] travis is unable to run monitorSync in 1 second? --- src/test/java/com/jnape/palatable/lambda/io/IOTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index c29f4caee..090be4520 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -352,7 +352,6 @@ public void monitorSync() throws InterruptedException { IO two = io(() -> { oneStarted.await(); accesses.add("two entered"); - Thread.sleep(10); accesses.add("two exited"); finishLine.countDown(); }); @@ -365,7 +364,7 @@ public void monitorSync() throws InterruptedException { start(); }}; - if (!finishLine.await(1, SECONDS)) + if (!finishLine.await(5, SECONDS)) fail("Expected threads to have completed by now"); assertEquals(asList("one entered", "one exited", "two entered", "two exited"), accesses); } From f33c3ac2bce7c0ceb394656a05e42e48bb36d86f Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 24 Jul 2019 18:50:28 -0500 Subject: [PATCH 212/348] Travis still can't pass this test on java 1.8 - 15s? --- src/test/java/com/jnape/palatable/lambda/io/IOTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 090be4520..41ef4ae62 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -364,7 +364,7 @@ public void monitorSync() throws InterruptedException { start(); }}; - if (!finishLine.await(5, SECONDS)) + if (!finishLine.await(15, SECONDS)) fail("Expected threads to have completed by now"); assertEquals(asList("one entered", "one exited", "two entered", "two exited"), accesses); } From 413f479f1cac75a583d89897b4c13af27c39884e Mon Sep 17 00:00:00 2001 From: John Napier Date: Sat, 10 Aug 2019 15:30:50 -0500 Subject: [PATCH 213/348] Adding Floobits badge to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 57b765ff7..65ba3cd42 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Build Status](https://travis-ci.com/palatable/lambda.svg?branch=master)](https://travis-ci.com/palatable/lambda) [![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda) [![Join the chat at https://gitter.im/palatable/lambda](https://badges.gitter.im/palatable/lambda.svg)](https://gitter.im/palatable/lambda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Floobits Status](https://floobits.com/jnape/lambda.svg)](https://floobits.com/jnape/lambda/redirect) Functional patterns for Java From 985ae079a6154fd3bd3edd774f25863aafef66a3 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 10 Aug 2019 15:50:53 -0500 Subject: [PATCH 214/348] adding floobits cruft --- .floo | 3 +++ .flooignore | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 .floo create mode 100644 .flooignore diff --git a/.floo b/.floo new file mode 100644 index 000000000..4775d1079 --- /dev/null +++ b/.floo @@ -0,0 +1,3 @@ +{ + "url": "https://floobits.com/jnape/lambda" +} \ No newline at end of file diff --git a/.flooignore b/.flooignore new file mode 100644 index 000000000..ed824d39a --- /dev/null +++ b/.flooignore @@ -0,0 +1,6 @@ +extern +node_modules +tmp +vendor +.idea/workspace.xml +.idea/misc.xml From 00c27d5e4f4f3eab5189c688dd2090d3d81f7626 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 15 Aug 2019 10:06:59 -0500 Subject: [PATCH 215/348] IO#memoize, for caching the first successful result from an IO --- CHANGELOG.md | 1 + pom.xml | 6 --- .../com/jnape/palatable/lambda/io/IO.java | 30 ++++++++++++ .../com/jnape/palatable/lambda/io/IOTest.java | 48 +++++++++++++++++++ 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6877c602e..0ec5f2bb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `IO#pin`, for pinning an `IO` to an `Executor` without yet executing it - `IO#fuse`, for fusing the fork opportunities of a given `IO` into a single linearized `IO` - `IO#exceptionallyIO`, like `exceptionally` but recover inside another `IO` +- `IO#memoize`, for memoizing an `IO` by caching its first successful result - `MonadError`, monads that can be thrown to and caught from ## [4.0.0] - 2019-05-20 diff --git a/pom.xml b/pom.xml index e4cb1a89f..63d3a701c 100644 --- a/pom.xml +++ b/pom.xml @@ -61,12 +61,6 @@ - - io.jaegertracing - jaeger-client - 0.35.5 - test - junit junit diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 3ac81450a..55e8413e6 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -297,6 +297,36 @@ public static IO pin(IO io, Executor executor) { return IO.externallyManaged(() -> io.unsafePerformAsyncIO(executor)); } + /** + * Given an {@link IO}, return an {@link IO} that wraps it, caches its first successful result, and guarantees that + * no subsequent interactions will happen with it afterwards, returning the cached result thereafter. Note that if + * the underlying {@link IO} throws, the failure will not be cached, so subsequent interactions with the memoized + * {@link IO} will again call through to the delegate until it completes normally. + * + * @param io the delegate {@link IO} + * @param the return type + * @return the memoized {@link IO} + */ + public static IO memoize(IO io) { + class Ref { + A value; + boolean computed; + } + Ref ref = new Ref(); + return join(io(() -> { + if (!ref.computed) { + return monitorSync(ref, io(() -> { + if (!ref.computed) { + A a = io.unsafePerformIO(); + ref.computed = true; + ref.value = a; + } + })).flatMap(constantly(io(() -> ref.value))); + } + return io(ref.value); + })); + } + /** * Static factory method for creating an {@link IO} that just returns a when performed. * diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 41ef4ae62..f22ed8b96 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -386,4 +386,52 @@ public void pin() { Thread chosenThread = IO.pin(currentThreadIO, Runnable::run).unsafePerformAsyncIO(executor).join(); assertEquals("Expected IO to run on the main Thread, but it didn't.", mainThread, chosenThread); } + + @Test + public void memoize() { + AtomicInteger counter = new AtomicInteger(0); + IO memoized = IO.memoize(io(counter::incrementAndGet)); + memoized.unsafePerformIO(); + memoized.unsafePerformIO(); + assertEquals(1, counter.get()); + } + + @Test + public void memoizationMutuallyExcludesSimultaneousComputation() throws InterruptedException { + AtomicInteger counter = new AtomicInteger(0); + + IO memoized = IO.memoize(io(() -> { + Thread.sleep(10); + return counter.incrementAndGet(); + })); + + Thread t1 = new Thread(memoized::unsafePerformIO) {{ + start(); + }}; + + Thread t2 = new Thread(memoized::unsafePerformIO) {{ + start(); + }}; + + t1.join(); + t2.join(); + + assertEquals(1, counter.get()); + } + + @Test + public void failuresAreNotMemoized() { + IllegalStateException exception = new IllegalStateException("not yet"); + AtomicInteger counter = new AtomicInteger(0); + IO io = IO.memoize(io(() -> { + int next = counter.incrementAndGet(); + if (next > 1) + return next; + throw exception; + })); + + assertEquals(left(exception), io.safe().unsafePerformIO()); + assertEquals((Integer) 2, io.unsafePerformIO()); + assertEquals((Integer) 2, io.unsafePerformIO()); + } } \ No newline at end of file From 64ae49b2d62fc57b4ffaeadb3079a031674932f9 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 15 Aug 2019 15:58:19 -0500 Subject: [PATCH 216/348] This is a safer order of assignment --- src/main/java/com/jnape/palatable/lambda/io/IO.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 55e8413e6..f00b4d1e9 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -317,9 +317,8 @@ class Ref { if (!ref.computed) { return monitorSync(ref, io(() -> { if (!ref.computed) { - A a = io.unsafePerformIO(); + ref.value = io.unsafePerformIO(); ref.computed = true; - ref.value = a; } })).flatMap(constantly(io(() -> ref.value))); } From f0bfb0492cbe16e988a6d322893f937a2d9be3e6 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 15 Aug 2019 17:17:49 -0500 Subject: [PATCH 217/348] More work on IOMatcher --- .../java/testsupport/matchers/IOMatcher.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/test/java/testsupport/matchers/IOMatcher.java b/src/test/java/testsupport/matchers/IOMatcher.java index 5785af090..080cedf2e 100644 --- a/src/test/java/testsupport/matchers/IOMatcher.java +++ b/src/test/java/testsupport/matchers/IOMatcher.java @@ -10,6 +10,7 @@ import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.io.IO.io; import static org.hamcrest.Matchers.anything; public final class IOMatcher extends TypeSafeMatcher> { @@ -26,24 +27,35 @@ private IOMatcher(Either, Matcher> matcher protected boolean matchesSafely(IO io) { Either res = io.safe().unsafePerformIO(); resultRef.set(res); - return res.match(t -> matcher.match(tMatcher -> tMatcher.matches(t), aMatcher -> false), - a -> matcher.match(tMatcher -> false, aMatcher -> aMatcher.matches(a))); + return res.match(t -> matcher.match(tMatcher -> tMatcher.matches(t), + aMatcher -> false), + a -> matcher.match(tMatcher -> false, + aMatcher -> aMatcher.matches(a))); } @Override public void describeTo(Description description) { - throw new UnsupportedOperationException(); + matcher.match(m -> io(() -> m.describeTo(description.appendText("IO throwing exception matching "))), + m -> io(() -> m.describeTo(description.appendText("IO yielding value matching ")))) + .unsafePerformIO(); } - public static IOMatcher isIOThat(Matcher matcher) { + @Override + protected void describeMismatchSafely(IO item, Description mismatchDescription) { + resultRef.get().match(t -> io(() -> mismatchDescription.appendText("IO threw " + t)), + a -> io(() -> mismatchDescription.appendText("IO yielded value " + a))) + .unsafePerformIO(); + } + + public static IOMatcher yieldsValue(Matcher matcher) { return new IOMatcher<>(right(matcher)); } - public static IOMatcher isIOThatCompletesNormally() { - return isIOThat(anything()); + public static IOMatcher completesNormally() { + return yieldsValue(anything()); } - public static IOMatcher isIOThatThrows(Matcher throwableMatcher) { + public static IOMatcher throwsException(Matcher throwableMatcher) { return new IOMatcher<>(left(throwableMatcher)); } } From 1b49bc65527ad277ebd17aece7c2f9bc49e0d3ad Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 17 Aug 2019 16:18:20 -0500 Subject: [PATCH 218/348] Tuple2-8#fromIterable --- CHANGELOG.md | 1 + .../jnape/palatable/lambda/adt/hlist/Tuple2.java | 15 +++++++++++++++ .../jnape/palatable/lambda/adt/hlist/Tuple3.java | 15 +++++++++++++++ .../jnape/palatable/lambda/adt/hlist/Tuple4.java | 15 +++++++++++++++ .../jnape/palatable/lambda/adt/hlist/Tuple5.java | 15 +++++++++++++++ .../jnape/palatable/lambda/adt/hlist/Tuple6.java | 15 +++++++++++++++ .../jnape/palatable/lambda/adt/hlist/Tuple7.java | 15 +++++++++++++++ .../jnape/palatable/lambda/adt/hlist/Tuple8.java | 15 +++++++++++++++ .../palatable/lambda/adt/hlist/Tuple2Test.java | 12 ++++++++++++ .../palatable/lambda/adt/hlist/Tuple3Test.java | 16 ++++++++++++++-- .../palatable/lambda/adt/hlist/Tuple4Test.java | 12 ++++++++++++ .../palatable/lambda/adt/hlist/Tuple5Test.java | 12 ++++++++++++ .../palatable/lambda/adt/hlist/Tuple6Test.java | 12 ++++++++++++ .../palatable/lambda/adt/hlist/Tuple7Test.java | 12 ++++++++++++ .../palatable/lambda/adt/hlist/Tuple8Test.java | 12 ++++++++++++ 15 files changed, 192 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ec5f2bb2..19e40a3c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `IO#exceptionallyIO`, like `exceptionally` but recover inside another `IO` - `IO#memoize`, for memoizing an `IO` by caching its first successful result - `MonadError`, monads that can be thrown to and caught from +- `Tuple2-8#fromIterable`, for populating a `TupleN` with the first `N` elements of an `Iterable` ## [4.0.0] - 2019-05-20 ### Changed 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 78bf332c3..0cc52aefd 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,8 +1,10 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Head; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -12,6 +14,7 @@ import java.util.Map; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; /** * A 2-element tuple product type, implemented as a specialized HList. Supports random access. @@ -161,4 +164,16 @@ public static Tuple2 fromEntry(Map.Entry entry) { public static Tuple2 fill(A a) { return tuple(a, a); } + + /** + * Return {@link Maybe#just(Object) just} the first two elements from the given {@link Iterable}, or + * {@link Maybe#nothing() nothing} if there are less than two elements. + * + * @param as the {@link Iterable} + * @param the {@link Iterable} element type + * @return {@link Maybe} the first two elements of the given {@link Iterable} + */ + public static Maybe> fromIterable(Iterable as) { + return uncons(as).flatMap(tail -> tail.traverse(Head::head, Maybe::just)); + } } 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 0e99a88b9..83ed9b54e 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,8 +1,10 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product3; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn2.Into; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -10,6 +12,7 @@ import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; /** * A 3-element tuple product type, implemented as a specialized HList. Supports random access. @@ -152,4 +155,16 @@ AppTrav extends Applicative> AppTrav traverse( public static Tuple3 fill(A a) { return tuple(a, a, a); } + + /** + * Return {@link Maybe#just(Object) just} the first three elements from the given {@link Iterable}, or + * {@link Maybe#nothing() nothing} if there are less than three elements. + * + * @param as the {@link Iterable} + * @param the {@link Iterable} element type + * @return {@link Maybe} the first three elements of the given {@link Iterable} + */ + public static Maybe> fromIterable(Iterable as) { + return uncons(as).flatMap(Into.into((head, tail) -> Tuple2.fromIterable(tail).fmap(t -> t.cons(head)))); + } } 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 1e99d3fd5..3f6ebe443 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,8 +1,10 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product4; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn2.Into; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -10,6 +12,7 @@ import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; /** * A 4-element tuple product type, implemented as a specialized HList. Supports random access. @@ -167,4 +170,16 @@ AppTrav extends Applicative> AppTrav traverse( public static Tuple4 fill(A a) { return tuple(a, a, a, a); } + + /** + * Return {@link Maybe#just(Object) just} the first four elements from the given {@link Iterable}, or + * {@link Maybe#nothing() nothing} if there are less than four elements. + * + * @param as the {@link Iterable} + * @param the {@link Iterable} element type + * @return {@link Maybe} the first four elements of the given {@link Iterable} + */ + public static Maybe> fromIterable(Iterable as) { + return uncons(as).flatMap(Into.into((head, tail) -> Tuple3.fromIterable(tail).fmap(t -> t.cons(head)))); + } } 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 0292831d2..c945b6b0b 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,8 +1,10 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product5; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn2.Into; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -10,6 +12,7 @@ import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; /** * A 5-element tuple product type, implemented as a specialized HList. Supports random access. @@ -187,4 +190,16 @@ AppTrav extends Applicative> AppTrav traverse( public static Tuple5 fill(A a) { return tuple(a, a, a, a, a); } + + /** + * Return {@link Maybe#just(Object) just} the first five elements from the given {@link Iterable}, or + * {@link Maybe#nothing() nothing} if there are less than five elements. + * + * @param as the {@link Iterable} + * @param the {@link Iterable} element type + * @return {@link Maybe} the first five elements of the given {@link Iterable} + */ + public static Maybe> fromIterable(Iterable as) { + return uncons(as).flatMap(Into.into((head, tail) -> Tuple4.fromIterable(tail).fmap(t -> t.cons(head)))); + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 86991a8ae..55e71e14a 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -1,8 +1,10 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product6; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn2.Into; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -10,6 +12,7 @@ import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; /** * A 6-element tuple product type, implemented as a specialized HList. Supports random access. @@ -208,4 +211,16 @@ AppTrav extends Applicative> AppTrav traverse( public static Tuple6 fill(A a) { return tuple(a, a, a, a, a, a); } + + /** + * Return {@link Maybe#just(Object) just} the first six elements from the given {@link Iterable}, or + * {@link Maybe#nothing() nothing} if there are less than six elements. + * + * @param as the {@link Iterable} + * @param the {@link Iterable} element type + * @return {@link Maybe} the first six elements of the given {@link Iterable} + */ + public static Maybe> fromIterable(Iterable as) { + return uncons(as).flatMap(Into.into((head, tail) -> Tuple5.fromIterable(tail).fmap(t -> t.cons(head)))); + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index 60d42664c..2de78379c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -1,8 +1,10 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product7; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn2.Into; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -10,6 +12,7 @@ import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; /** * A 7-element tuple product type, implemented as a specialized HList. Supports random access. @@ -229,4 +232,16 @@ AppTrav extends Applicative> AppTrav traverse( public static Tuple7 fill(A a) { return tuple(a, a, a, a, a, a, a); } + + /** + * Return {@link Maybe#just(Object) just} the first seven elements from the given {@link Iterable}, or + * {@link Maybe#nothing() nothing} if there are less than seven elements. + * + * @param as the {@link Iterable} + * @param the {@link Iterable} element type + * @return {@link Maybe} the first seven elements of the given {@link Iterable} + */ + public static Maybe> fromIterable(Iterable as) { + return uncons(as).flatMap(Into.into((head, tail) -> Tuple6.fromIterable(tail).fmap(t -> t.cons(head)))); + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 81054635e..898124fa8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -1,8 +1,10 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.product.Product8; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn2.Into; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -10,6 +12,7 @@ import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; /** * An 8-element tuple product type, implemented as a specialized HList. Supports random access. @@ -249,4 +252,16 @@ AppTrav extends Applicative> AppTrav traverse( public static Tuple8 fill(A a) { return tuple(a, a, a, a, a, a, a, a); } + + /** + * Return {@link Maybe#just(Object) just} the first eight elements from the given {@link Iterable}, or + * {@link Maybe#nothing() nothing} if there are less than eight elements. + * + * @param as the {@link Iterable} + * @param the {@link Iterable} element type + * @return {@link Maybe} the first seven elements of the given {@link Iterable} + */ + public static Maybe> fromIterable(Iterable as) { + return uncons(as).flatMap(Into.into((head, tail) -> Tuple7.fromIterable(tail).fmap(t -> t.cons(head)))); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index 75d4bcbe2..98ace9007 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -15,8 +15,13 @@ import java.util.HashMap; import java.util.Map; +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.singletonHList; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.only; import static org.mockito.Mockito.spy; @@ -115,4 +120,11 @@ public void flatMapPrecedence() { Fn1> b = x -> tuple("bar", x + 1); assertEquals(tuple("foo", 2), a.flatMap(b)); } + + @Test + public void fromIterable() { + assertEquals(nothing(), Tuple2.fromIterable(emptyList())); + assertEquals(nothing(), Tuple2.fromIterable(singletonList(1))); + assertEquals(just(tuple(1, 1)), Tuple2.fromIterable(repeat(1))); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java index d52b407bb..0ae6c5893 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java @@ -12,7 +12,12 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; +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.functions.builtin.fn1.Repeat.repeat; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -58,8 +63,8 @@ public void accessors() { @Test public void randomAccess() { - Tuple2 spiedTail = spy(tuple("second", "third")); - Tuple3 tuple3 = new Tuple3<>("first", spiedTail); + Tuple2 spiedTail = spy(tuple("second", "third")); + Tuple3 tuple3 = new Tuple3<>("first", spiedTail); verify(spiedTail, times(1))._1(); verify(spiedTail, times(1))._2(); @@ -93,4 +98,11 @@ public void flatMapPrecedence() { Fn1> b = x -> tuple("bar", 2, x + 1); assertEquals(tuple("foo", 1, 3), a.flatMap(b)); } + + @Test + public void fromIterable() { + assertEquals(nothing(), Tuple3.fromIterable(emptyList())); + assertEquals(nothing(), Tuple3.fromIterable(singletonList(1))); + assertEquals(just(tuple(1, 1, 1)), Tuple3.fromIterable(repeat(1))); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java index 4e0fa9659..be5168ca2 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java @@ -12,7 +12,12 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; +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.functions.builtin.fn1.Repeat.repeat; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -96,4 +101,11 @@ public void flatMapPrecedence() { Fn1> b = x -> tuple("bar", 2, 3, x + 1); assertEquals(tuple("foo", 1, 2, 4), a.flatMap(b)); } + + @Test + public void fromIterable() { + assertEquals(nothing(), Tuple4.fromIterable(emptyList())); + assertEquals(nothing(), Tuple4.fromIterable(singletonList(1))); + assertEquals(just(tuple(1, 1, 1, 1)), Tuple4.fromIterable(repeat(1))); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index 45e4edc67..7b63b2657 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -13,7 +13,12 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; +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.functions.builtin.fn1.Repeat.repeat; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -102,4 +107,11 @@ public void flatMapPrecedence() { Fn1> b = x -> tuple("bar", 2, 3, 4, x + 1); assertEquals(tuple("foo", 1, 2, 3, 5), a.flatMap(b)); } + + @Test + public void fromIterable() { + assertEquals(nothing(), Tuple5.fromIterable(emptyList())); + assertEquals(nothing(), Tuple5.fromIterable(singletonList(1))); + assertEquals(just(tuple(1, 1, 1, 1, 1)), Tuple5.fromIterable(repeat(1))); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index 1fb7ab578..bad1a776d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -13,7 +13,12 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; +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.functions.builtin.fn1.Repeat.repeat; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -106,4 +111,11 @@ public void flatMapPrecedence() { Fn1> b = x -> tuple("bar", 2, 3, 4, 5, x + 1); assertEquals(tuple("foo", 1, 2, 3, 4, 6), a.flatMap(b)); } + + @Test + public void fromIterable() { + assertEquals(nothing(), Tuple6.fromIterable(emptyList())); + assertEquals(nothing(), Tuple6.fromIterable(singletonList(1))); + assertEquals(just(tuple(1, 1, 1, 1, 1, 1)), Tuple6.fromIterable(repeat(1))); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index 6203fe15e..07fbe09f5 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -13,7 +13,12 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; +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.functions.builtin.fn1.Repeat.repeat; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -109,4 +114,11 @@ public void flatMapPrecedence() { Fn1> b = x -> tuple("bar", 2, 3, 4, 5, 6, x + 1); assertEquals(tuple("foo", 1, 2, 3, 4, 5, 7), a.flatMap(b)); } + + @Test + public void fromIterable() { + assertEquals(nothing(), Tuple7.fromIterable(emptyList())); + assertEquals(nothing(), Tuple7.fromIterable(singletonList(1))); + assertEquals(just(tuple(1, 1, 1, 1, 1, 1, 1)), Tuple7.fromIterable(repeat(1))); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java index 6c788a83d..c10cecdfd 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java @@ -13,7 +13,12 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; +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.functions.builtin.fn1.Repeat.repeat; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -114,4 +119,11 @@ public void flatMapPrecedence() { x -> tuple("bar", 2, 3, 4, 5, 6, 7, x + 1); assertEquals(tuple("foo", 1, 2, 3, 4, 5, 6, 8), a.flatMap(b)); } + + @Test + public void fromIterable() { + assertEquals(nothing(), Tuple8.fromIterable(emptyList())); + assertEquals(nothing(), Tuple8.fromIterable(singletonList(1))); + assertEquals(just(tuple(1, 1, 1, 1, 1, 1, 1, 1)), Tuple8.fromIterable(repeat(1))); + } } \ No newline at end of file From 3093d93d3c981eb1cde0c03b12afbbbe1fa525d8 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 17 Aug 2019 17:05:59 -0500 Subject: [PATCH 219/348] Replacing unsafe calls in tests with IOMatcher interactions --- .../lambda/functions/EffectTest.java | 34 ++++++++------ .../functions/builtin/fn2/AlterTest.java | 12 +++-- .../functions/builtin/fn2/UntilTest.java | 9 ++-- .../functions/builtin/fn3/BracketTest.java | 45 ++++++++----------- .../lambda/monoid/builtin/RunAllTest.java | 10 +++-- .../lambda/semigroup/builtin/RunAllTest.java | 8 ++-- 6 files changed, 62 insertions(+), 56 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java index 0609643f5..456d2619c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/EffectTest.java @@ -12,11 +12,16 @@ import static com.jnape.palatable.lambda.functions.Effect.effect; import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Alter.alter; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Sequence.sequence; import static com.jnape.palatable.lambda.functions.specialized.SideEffect.sideEffect; import static com.jnape.palatable.lambda.io.IO.io; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; +import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IOMatcher.yieldsValue; public class EffectTest { @@ -25,16 +30,17 @@ public void covariantReturns() { List results = new ArrayList<>(); Effect effect = fromConsumer(results::add); - Effect diMapL = effect.diMapL(Object::toString); - Effect contraMap = effect.contraMap(Object::toString); + Effect diMapL = effect.diMapL(Object::toString); + Effect contraMap = effect.contraMap(Object::toString); Effect stringEffect = effect.discardR(constantly("1")); - effect.apply("1").unsafePerformIO(); - diMapL.apply("2").unsafePerformIO(); - contraMap.apply("3").unsafePerformIO(); - stringEffect.apply("4").unsafePerformIO(); - - assertEquals(asList("1", "2", "3", "4"), results); + assertThat(sequence(asList(effect.apply("1"), + diMapL.apply("2"), + contraMap.apply("3"), + stringEffect.apply("4")), + IO::io) + .fmap(constantly(results)), + yieldsValue(equalTo(asList("1", "2", "3", "4")))); } @Test @@ -42,8 +48,8 @@ public void andThen() { AtomicInteger counter = new AtomicInteger(); Effect inc = c -> io(sideEffect(c::incrementAndGet)); - inc.andThen(inc).apply(counter).unsafePerformIO(); - assertEquals(2, counter.get()); + assertThat(alter(inc.andThen(inc), counter).fmap(AtomicInteger::get), + yieldsValue(equalTo(2))); } @Test @@ -51,12 +57,12 @@ public void staticFactoryMethods() { AtomicInteger counter = new AtomicInteger(); Effect sideEffect = effect(counter::incrementAndGet); - sideEffect.apply("foo").unsafePerformIO(); - assertEquals(1, counter.get()); + assertThat(sideEffect.apply("foo").flatMap(constantly(io(counter::get))), + yieldsValue(equalTo(1))); Effect fnEffect = Effect.fromConsumer(AtomicInteger::incrementAndGet); - fnEffect.apply(counter).unsafePerformIO(); - assertEquals(2, counter.get()); + assertThat(fnEffect.apply(counter).flatMap(constantly(io(counter::get))), + yieldsValue(equalTo(2))); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java index 9bff92fa4..5baa26fa1 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java @@ -7,15 +7,19 @@ import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functions.builtin.fn2.Alter.alter; import static java.util.Collections.singletonList; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IOMatcher.yieldsValue; public class AlterTest { @Test public void altersInput() { ArrayList input = new ArrayList<>(); - assertSame(input, alter(fromConsumer(xs -> xs.add("foo")), input).unsafePerformIO()); - assertEquals(singletonList("foo"), input); + assertThat(alter(fromConsumer(xs -> xs.add("foo")), input), + yieldsValue(allOf(sameInstance(input), + equalTo(singletonList("foo"))))); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UntilTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UntilTest.java index 3a6e1e953..90c63dbee 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UntilTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UntilTest.java @@ -7,18 +7,21 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Until.until; import static com.jnape.palatable.lambda.io.IO.io; -import static org.junit.Assert.assertEquals; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IOMatcher.yieldsValue; public class UntilTest { @Test public void repeatedlyExecutesUntilPredicateMatches() { AtomicInteger counter = new AtomicInteger(0); - assertEquals((Integer) 10, until(x -> x == 10, io(counter::getAndIncrement)).unsafePerformIO()); + assertThat(until(x -> x == 10, io(counter::getAndIncrement)), + yieldsValue(equalTo(10))); } @Test public void predicateThatImmediatelyMatchesDoesNotChangeIO() { - assertEquals((Integer) 0, until(constantly(true), io(0)).unsafePerformIO()); + assertThat(until(constantly(true), io(0)), yieldsValue(equalTo(0))); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java index 389ca5508..9e2f373a1 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/BracketTest.java @@ -6,11 +6,15 @@ import java.util.concurrent.atomic.AtomicInteger; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn3.Bracket.bracket; import static com.jnape.palatable.lambda.io.IO.io; +import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IOMatcher.throwsException; +import static testsupport.matchers.IOMatcher.yieldsValue; public class BracketTest { @@ -26,7 +30,7 @@ public void cleanupHappyPath() { IO hashIO = bracket(io(() -> count), c -> io(c::incrementAndGet), c -> io(c::hashCode)); assertEquals(0, count.get()); - assertEquals((Integer) count.hashCode(), hashIO.unsafePerformIO()); + assertThat(hashIO, yieldsValue(equalTo(count.hashCode()))); assertEquals(1, count.get()); } @@ -35,28 +39,19 @@ public void cleanupSadPath() { IllegalStateException thrown = new IllegalStateException("kaboom"); IO hashIO = bracket(io(count), c -> io(c::incrementAndGet), c -> io(() -> {throw thrown;})); - try { - hashIO.unsafePerformIO(); - fail("Expected exception to be raised"); - } catch (IllegalStateException actual) { - assertEquals(thrown, actual); - assertEquals(1, count.get()); - } + assertThat(hashIO, throwsException(equalTo(thrown))); + assertEquals(1, count.get()); } @Test public void cleanupOnlyRunsIfInitialIORuns() { IllegalStateException thrown = new IllegalStateException("kaboom"); IO hashIO = bracket(io(() -> {throw thrown;}), - __ -> io(count::incrementAndGet), - __ -> io(count::incrementAndGet)); - try { - hashIO.unsafePerformIO(); - fail("Expected exception to be raised"); - } catch (IllegalStateException actual) { - assertEquals(thrown, actual); - assertEquals(0, count.get()); - } + constantly(io(count::incrementAndGet)), + constantly(io(count::incrementAndGet))); + + assertThat(hashIO, throwsException(equalTo(thrown))); + assertEquals(0, count.get()); } @Test @@ -64,14 +59,10 @@ public void errorsInCleanupAreAddedToBodyErrors() { IllegalStateException bodyError = new IllegalStateException("kaboom"); IllegalStateException cleanupError = new IllegalStateException("KABOOM"); IO hashIO = bracket(io(count), - c -> io(() -> {throw cleanupError;}), - c -> io(() -> {throw bodyError;})); - try { - hashIO.unsafePerformIO(); - fail("Expected exception to be raised"); - } catch (IllegalStateException actual) { - assertEquals(bodyError, actual); - assertArrayEquals(new Throwable[]{cleanupError}, actual.getSuppressed()); - } + constantly(io(() -> {throw cleanupError;})), + constantly(io(() -> {throw bodyError;}))); + + assertThat(hashIO, throwsException(equalTo(bodyError))); + assertArrayEquals(new Throwable[]{cleanupError}, bodyError.getSuppressed()); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java index c0e9f6d17..c7460e53e 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RunAllTest.java @@ -5,14 +5,16 @@ import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monoid.builtin.RunAll.runAll; -import static org.junit.Assert.assertEquals; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IOMatcher.yieldsValue; public class RunAllTest { @Test public void monoid() { - Monoid add = Monoid.monoid((x, y) -> x + y, 0); - assertEquals((Integer) 3, runAll(add).apply(io(1), io(2)).unsafePerformIO()); - assertEquals((Integer) 0, runAll(add).identity().unsafePerformIO()); + Monoid add = Monoid.monoid(Integer::sum, 0); + assertThat(runAll(add).apply(io(1), io(2)), yieldsValue(equalTo(3))); + assertThat(runAll(add).identity(), yieldsValue(equalTo(0))); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java index 329fe8429..2733690c4 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RunAllTest.java @@ -1,17 +1,17 @@ package com.jnape.palatable.lambda.semigroup.builtin; -import com.jnape.palatable.lambda.semigroup.Semigroup; import org.junit.Test; import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.semigroup.builtin.RunAll.runAll; -import static org.junit.Assert.assertEquals; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IOMatcher.yieldsValue; public class RunAllTest { @Test public void semigroup() { - Semigroup add = (x, y) -> x + y; - assertEquals((Integer) 3, runAll(add).apply(io(1), io(2)).unsafePerformIO()); + assertThat(runAll(Integer::sum).apply(io(1), io(2)), yieldsValue(equalTo(3))); } } \ No newline at end of file From ae1fc258e42b695ddced68a85cc90d8cf08830f0 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 17 Aug 2019 18:00:07 -0500 Subject: [PATCH 220/348] Sealing ReaderT --- .../monad/transformer/builtin/ReaderT.java | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index d905236f0..acda7e825 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -19,17 +19,25 @@ * @param the returned {@link Monad} * @param the embedded output type */ -public interface ReaderT, A> extends +public final class ReaderT, A> implements MonadT, M, A, ReaderT>, Cartesian> { + private final Fn1> fn; + + private ReaderT(Fn1> fn) { + this.fn = fn; + } + /** * Run the computation represented by this {@link ReaderT}. * * @param r the input * @return the {¬@link Monad monadic} embedding {@link Monad}<A, M> */ - Monad runReaderT(R r); + public > MA runReaderT(R r) { + return fn.apply(r).coerce(); + } /** * Map the current {@link Monad monadic} embedding to a new one in a potentially different {@link Monad}. @@ -40,7 +48,7 @@ public interface ReaderT, A> extends * @param the new embedded result * @return the mapped {@link ReaderT} */ - default , N extends Monad, B> ReaderT mapReaderT( + public , N extends Monad, B> ReaderT mapReaderT( Fn1> fn) { return readerT(r -> fn.apply(runReaderT(r).coerce())); } @@ -49,7 +57,7 @@ default , N extends Monad, B> ReaderT mapR * {@inheritDoc} */ @Override - default , FGA extends Monad>> FGA run() { + public , FGA extends Monad>> FGA run() { return Fn1.fn1(r -> runReaderT(r).coerce()).coerce(); } @@ -57,7 +65,7 @@ default , N extends Monad, B> ReaderT mapR * {@inheritDoc} */ @Override - default ReaderT flatMap(Fn1>> f) { + public ReaderT flatMap(Fn1>> f) { return readerT(r -> runReaderT(r).flatMap(a -> f.apply(a).>coerce().runReaderT(r))); } @@ -65,7 +73,7 @@ default ReaderT flatMap(Fn1 ReaderT pure(B b) { + public ReaderT pure(B b) { return readerT(r -> runReaderT(r).pure(b)); } @@ -73,7 +81,7 @@ default ReaderT pure(B b) { * {@inheritDoc} */ @Override - default ReaderT fmap(Fn1 fn) { + public ReaderT fmap(Fn1 fn) { return MonadT.super.fmap(fn).coerce(); } @@ -81,7 +89,7 @@ default ReaderT fmap(Fn1 fn) { * {@inheritDoc} */ @Override - default ReaderT zip(Applicative, ReaderT> appFn) { + public ReaderT zip(Applicative, ReaderT> appFn) { return readerT(r -> runReaderT(r).zip(appFn.>>coerce().runReaderT(r))); } @@ -89,7 +97,7 @@ default ReaderT zip(Applicative, Reader * {@inheritDoc} */ @Override - default Lazy> lazyZip( + public Lazy> lazyZip( Lazy, ReaderT>> lazyAppFn) { return lazyAppFn.fmap(this::zip); } @@ -98,7 +106,7 @@ default Lazy> lazyZip( * {@inheritDoc} */ @Override - default ReaderT discardL(Applicative> appB) { + public ReaderT discardL(Applicative> appB) { return MonadT.super.discardL(appB).coerce(); } @@ -106,7 +114,7 @@ default ReaderT discardL(Applicative> appB) { * {@inheritDoc} */ @Override - default ReaderT discardR(Applicative> appB) { + public ReaderT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } @@ -114,7 +122,7 @@ default ReaderT discardR(Applicative> appB) { * {@inheritDoc} */ @Override - default ReaderT diMap(Fn1 lFn, Fn1 rFn) { + public ReaderT diMap(Fn1 lFn, Fn1 rFn) { return readerT(q -> runReaderT(lFn.apply(q)).fmap(rFn)); } @@ -122,7 +130,7 @@ default ReaderT diMap(Fn1 lFn, Fn1 ReaderT diMapL(Fn1 fn) { + public ReaderT diMapL(Fn1 fn) { return (ReaderT) Cartesian.super.diMapL(fn); } @@ -130,7 +138,7 @@ default ReaderT diMapL(Fn1 fn) { * {@inheritDoc} */ @Override - default ReaderT diMapR(Fn1 fn) { + public ReaderT diMapR(Fn1 fn) { return (ReaderT) Cartesian.super.diMapR(fn); } @@ -138,7 +146,7 @@ default ReaderT diMapR(Fn1 fn) { * {@inheritDoc} */ @Override - default ReaderT contraMap(Fn1 fn) { + public ReaderT contraMap(Fn1 fn) { return (ReaderT) Cartesian.super.contraMap(fn); } @@ -146,7 +154,7 @@ default ReaderT contraMap(Fn1 fn) { * {@inheritDoc} */ @Override - default ReaderT, M, Tuple2> cartesian() { + public ReaderT, M, Tuple2> cartesian() { return readerT(into((c, r) -> runReaderT(r).fmap(tupler(c)))); } @@ -154,7 +162,7 @@ default ReaderT, M, Tuple2> cartesian() { * {@inheritDoc} */ @Override - default ReaderT> carry() { + public ReaderT> carry() { return (ReaderT>) Cartesian.super.carry(); } @@ -167,7 +175,7 @@ default ReaderT> carry() { * @param the embedded output type * @return the {@link ReaderT} */ - static , A> ReaderT readerT(Fn1> fn) { - return fn::apply; + public static , A> ReaderT readerT(Fn1> fn) { + return new ReaderT<>(fn); } } From 78efc11fdad431fd11ea6b3eef5b1b50cc7a9c2c Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 17 Aug 2019 18:01:00 -0500 Subject: [PATCH 221/348] Updating CHANGELOG to call out breaking type signature changes --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19e40a3c8..0025110c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Changed -- `MonadT` is now witnessed by a parameter for better subtyping +- ***Breaking Change***: `MonadT` is now witnessed by a parameter for better subtyping - `Alter` now merely requires an `Fn1` instead of an explicit `Effect` - `IO` now internally trampolines all forms of composition, including lazyZip; sequencing very large iterables of IO will work, if you have the heap, and From dea2016b16736e46f8bf5cf540aa17aa44f099ab Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 19 Aug 2019 11:43:41 -0500 Subject: [PATCH 222/348] throw/catch is much more important than auto-suppression --- .../com/jnape/palatable/lambda/io/IO.java | 25 +++++-------------- .../com/jnape/palatable/lambda/io/IOTest.java | 23 +++++++++++------ 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index f00b4d1e9..00f4faf8f 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -17,8 +17,6 @@ import java.util.concurrent.Executor; import static com.jnape.palatable.lambda.adt.Either.left; -import static com.jnape.palatable.lambda.adt.Try.failure; -import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; @@ -190,28 +188,17 @@ public final IO catchError(Fn1>> return new IO() { @Override public A unsafePerformIO() { - return trying(fn0(IO.this::unsafePerformIO)) - .recover(t -> trying(fn0(recoveryFn.apply(t).>coerce()::unsafePerformIO)) - .fmap(Try::success) - .recover(t2 -> { - t.addSuppressed(t2); - return failure(t); - }) - .orThrow()); + return Try.trying(IO.this::unsafePerformIO) + .catchError(t -> Try.trying(recoveryFn.apply(t).>coerce()::unsafePerformIO)) + .orThrow(); } @Override public CompletableFuture unsafePerformAsyncIO(Executor executor) { return IO.this.unsafePerformAsyncIO(executor) - .thenApply(CompletableFuture::completedFuture) - .exceptionally(t -> recoveryFn.apply(t).>coerce().unsafePerformAsyncIO(executor) - .thenApply(CompletableFuture::completedFuture) - .exceptionally(t2 -> { - t.addSuppressed(t2); - return new CompletableFuture() {{ - completeExceptionally(t); - }}; - }).thenCompose(f -> f)) + .handle((a, t) -> t == null + ? completedFuture(a) + : recoveryFn.apply(t).>coerce().unsafePerformAsyncIO(executor)) .thenCompose(f -> f); } }; diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index f22ed8b96..ba53b6870 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; @@ -48,6 +49,7 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static testsupport.Constants.STACK_EXPLODING_NUMBER; @@ -149,16 +151,21 @@ public void catchError() { } @Test - public void catchErrorSuppressesSecondaryThrowable() { - Throwable foo = new UnsupportedOperationException("foo"); - Throwable bar = new UnsupportedOperationException("bar"); + public void catchAndRethrow() { + IllegalStateException expected = new IllegalStateException("expected"); + IO catchAndRethrow = IO.throwing(expected) + .catchError(IO::throwing); try { - IO.throwing(foo).catchError(t -> IO.throwing(bar)).unsafePerformIO(); - fail("Expected exception to have been thrown, but wasn't."); - } catch (UnsupportedOperationException expected) { - assertEquals(expected, foo); - assertArrayEquals(new Throwable[]{bar}, expected.getSuppressed()); + catchAndRethrow.unsafePerformIO(); + } catch (Exception actual) { + assertSame(expected, actual); + } + + try { + catchAndRethrow.unsafePerformAsyncIO().join(); + } catch (CompletionException actual) { + assertEquals(expected, actual.getCause()); } } From 7b179a53372645ce276741af8abfe8f2c3d4c98f Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 19 Aug 2019 14:41:42 -0500 Subject: [PATCH 223/348] At least now I'll get a sense of what's happening on Travis --- .../java/com/jnape/palatable/lambda/io/IOTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index ba53b6870..949a5f091 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -348,31 +348,31 @@ public void monitorSync() throws InterruptedException { CountDownLatch oneStarted = new CountDownLatch(1); CountDownLatch finishLine = new CountDownLatch(2); - IO one = io(() -> { + IO one = IO.monitorSync(lock, io(() -> { accesses.add("one entered"); oneStarted.countDown(); Thread.sleep(10); accesses.add("one exited"); finishLine.countDown(); - }); + })); - IO two = io(() -> { + IO two = IO.monitorSync(lock, io(() -> { oneStarted.await(); accesses.add("two entered"); accesses.add("two exited"); finishLine.countDown(); - }); + })); - new Thread(IO.monitorSync(lock, one)::unsafePerformIO) {{ + new Thread(one::unsafePerformIO) {{ start(); }}; - new Thread(IO.monitorSync(lock, two)::unsafePerformIO) {{ + new Thread(two::unsafePerformIO) {{ start(); }}; if (!finishLine.await(15, SECONDS)) - fail("Expected threads to have completed by now"); + fail("Expected threads to have completed by now, only got this far: " + accesses); assertEquals(asList("one entered", "one exited", "two entered", "two exited"), accesses); } From 6dc9ee1722963f3a818e2e88a856143404c1ac07 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 19 Aug 2019 18:24:17 -0500 Subject: [PATCH 224/348] Updating LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index b35067105..fb5630322 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2018 John Napier (jnape) +Copyright (c) 2019 John Napier (jnape) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From 817af07d79e38dc06d77bec8a03053856094ce70 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 22 Aug 2019 10:35:05 -0500 Subject: [PATCH 225/348] Adding Pure implementations for every Monad as a static method on its class --- .../jnape/palatable/lambda/adt/Either.java | 10 ++ .../com/jnape/palatable/lambda/adt/Maybe.java | 10 ++ .../com/jnape/palatable/lambda/adt/These.java | 11 ++ .../com/jnape/palatable/lambda/adt/Try.java | 29 ++-- .../palatable/lambda/adt/choice/Choice2.java | 11 ++ .../palatable/lambda/adt/choice/Choice3.java | 14 +- .../palatable/lambda/adt/choice/Choice4.java | 13 ++ .../palatable/lambda/adt/choice/Choice5.java | 14 ++ .../palatable/lambda/adt/choice/Choice6.java | 15 ++ .../palatable/lambda/adt/choice/Choice7.java | 16 +++ .../palatable/lambda/adt/choice/Choice8.java | 16 +++ .../lambda/adt/hlist/SingletonHList.java | 37 +++++ .../palatable/lambda/adt/hlist/Tuple2.java | 71 ++++++++++ .../palatable/lambda/adt/hlist/Tuple3.java | 73 ++++++++++ .../palatable/lambda/adt/hlist/Tuple4.java | 84 +++++++++++ .../palatable/lambda/adt/hlist/Tuple5.java | 95 +++++++++++++ .../palatable/lambda/adt/hlist/Tuple6.java | 107 ++++++++++++++ .../palatable/lambda/adt/hlist/Tuple7.java | 118 ++++++++++++++++ .../palatable/lambda/adt/hlist/Tuple8.java | 132 ++++++++++++++++++ .../jnape/palatable/lambda/functions/Fn1.java | 11 ++ .../functions/recursion/RecursiveResult.java | 17 ++- .../lambda/functor/builtin/Compose.java | 16 +++ .../lambda/functor/builtin/Const.java | 20 +++ .../lambda/functor/builtin/Identity.java | 10 ++ .../lambda/functor/builtin/Lazy.java | 10 ++ .../lambda/functor/builtin/Market.java | 18 +++ .../lambda/functor/builtin/State.java | 16 +++ .../lambda/functor/builtin/Tagged.java | 48 ++++++- .../com/jnape/palatable/lambda/io/IO.java | 13 ++ .../monad/transformer/builtin/EitherT.java | 18 +++ .../monad/transformer/builtin/IdentityT.java | 17 +++ .../monad/transformer/builtin/LazyT.java | 17 +++ .../monad/transformer/builtin/MaybeT.java | 17 +++ .../monad/transformer/builtin/ReaderT.java | 18 +++ .../jnape/palatable/lambda/optics/Iso.java | 31 +++- .../jnape/palatable/lambda/optics/Lens.java | 15 ++ .../jnape/palatable/lambda/optics/Prism.java | 22 ++- .../lambda/traversable/LambdaIterable.java | 15 ++ .../palatable/lambda/adt/EitherTest.java | 6 + .../jnape/palatable/lambda/adt/MaybeTest.java | 7 + .../jnape/palatable/lambda/adt/TheseTest.java | 7 +- .../jnape/palatable/lambda/adt/TryTest.java | 7 + .../lambda/adt/choice/Choice2Test.java | 6 + .../lambda/adt/choice/Choice3Test.java | 6 + .../lambda/adt/choice/Choice4Test.java | 6 + .../lambda/adt/choice/Choice5Test.java | 6 + .../lambda/adt/choice/Choice6Test.java | 7 + .../lambda/adt/choice/Choice7Test.java | 7 + .../lambda/adt/choice/Choice8Test.java | 7 + .../lambda/adt/hlist/SingletonHListTest.java | 7 + .../lambda/adt/hlist/Tuple2Test.java | 7 + .../lambda/adt/hlist/Tuple3Test.java | 7 + .../lambda/adt/hlist/Tuple4Test.java | 7 + .../lambda/adt/hlist/Tuple5Test.java | 7 + .../lambda/adt/hlist/Tuple6Test.java | 7 + .../lambda/adt/hlist/Tuple7Test.java | 8 ++ .../lambda/adt/hlist/Tuple8Test.java | 8 ++ .../palatable/lambda/functions/Fn1Test.java | 6 + .../recursion/RecursiveResultTest.java | 8 ++ .../lambda/functor/builtin/ComposeTest.java | 9 ++ .../lambda/functor/builtin/ConstTest.java | 10 ++ .../lambda/functor/builtin/IdentityTest.java | 10 ++ .../lambda/functor/builtin/LazyTest.java | 7 + .../lambda/functor/builtin/MarketTest.java | 10 ++ .../lambda/functor/builtin/StateTest.java | 6 + .../lambda/functor/builtin/TaggedTest.java | 27 ++++ .../com/jnape/palatable/lambda/io/IOTest.java | 7 + .../transformer/builtin/EitherTTest.java | 8 ++ .../transformer/builtin/IdentityTTest.java | 8 ++ .../monad/transformer/builtin/LazyTTest.java | 10 ++ .../monad/transformer/builtin/MaybeTTest.java | 9 ++ .../transformer/builtin/ReaderTTest.java | 8 ++ .../lambda/monoid/builtin/ComposeTest.java | 2 +- .../palatable/lambda/optics/IsoTest.java | 7 + .../palatable/lambda/optics/PrismTest.java | 8 ++ .../traversable/LambdaIterableTest.java | 10 ++ 76 files changed, 1500 insertions(+), 25 deletions(-) create mode 100644 src/test/java/com/jnape/palatable/lambda/functor/builtin/TaggedTest.java 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 be7f01111..ba75da155 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek2; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; @@ -403,6 +404,15 @@ public static Either right(R r) { return new Right<>(r); } + /** + * The canonical {@link Pure} instance for {@link Either}. + * + * @return the {@link Pure} instance + */ + public static Pure> pureEither() { + return Either::right; + } + private static final class Left extends Either { private final L l; diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index 6b92e13ca..d2cb62ed8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -8,6 +8,7 @@ import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -296,6 +297,15 @@ public static Maybe nothing() { return (Maybe) Nothing.INSTANCE; } + /** + * The canonical {@link Pure} instance for {@link Maybe}. + * + * @return the {@link Pure} instance + */ + public static Pure> pureMaybe() { + return Maybe::just; + } + private static final class Nothing extends Maybe { private static final Nothing INSTANCE = new Nothing<>(); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index 5f8e67270..e1aa94c7e 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct3; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -164,6 +165,16 @@ public static These both(A a, B b) { return new Both<>(tuple(a, b)); } + /** + * The canonical {@link Pure} instance for {@link These}. + * + * @param the first possible type + * @return the {@link Pure} instance + */ + public static Pure> pureThese() { + return These::b; + } + private static final class _A extends These { private final A a; diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index 511dd26e0..aeb56779c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -3,6 +3,8 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Downcast; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -44,10 +46,9 @@ private Try() { * @param recoveryFn the function mapping the {@link Throwable} to the result * @return a new {@link Try} instance around either the original successful result or the mapped result */ - @SuppressWarnings("unchecked") public final Try catching(Class throwableType, Fn1 recoveryFn) { - return catching(throwableType::isInstance, t -> recoveryFn.apply((S) t)); + return catching(throwableType::isInstance, t -> recoveryFn.apply(Downcast.downcast(t))); } /** @@ -76,13 +77,13 @@ public final Try catching(Fn1 predicate * rules above */ public final Try ensuring(SideEffect sideEffect) { - return match(t -> trying(sideEffect) - .>fmap(constantly(failure(t))) - .recover(t2 -> { - t.addSuppressed(t2); - return failure(t); - }), - a -> trying(sideEffect).fmap(constantly(a))); + return this.>match(t -> trying(sideEffect) + .>fmap(constantly(failure(t))) + .recover(t2 -> { + t.addSuppressed(t2); + return failure(t); + }), + a -> trying(sideEffect).fmap(constantly(a))); } /** @@ -133,7 +134,6 @@ public final A orThrow() throws T { */ public abstract A orThrow(Fn1 fn) throws T; - /** * If this is a success, wrap the value in a {@link Maybe#just} and return it. Otherwise, return {@link * Maybe#nothing()}. @@ -381,6 +381,15 @@ public static withResources(() -> cFn.apply(b), fn::apply)); } + /** + * The canonical {@link Pure} instance for {@link Try}. + * + * @return the {@link Pure} instance + */ + public static Pure> pureTry() { + return Try::success; + } + private static final class Failure extends Try { private final Throwable t; diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index 7366881c2..1766585d2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.Functor; @@ -181,6 +182,16 @@ public static Choice2 b(B b) { return new _B<>(b); } + /** + * The canonical {@link Pure} instance for {@link Choice2}. + * + * @param the first possible type + * @return the {@link Pure} instance + */ + public static Pure> pureChoice() { + return Choice2::b; + } + private static final class _A extends Choice2 { private final A a; diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 5e4388419..c3fbb4fe4 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple3; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.Functor; @@ -198,6 +199,17 @@ public static Choice3 c(C c) { return new _C<>(c); } + /** + * The canonical {@link Pure} instance for {@link Choice3}. + * + * @param the first possible type + * @param the second possible type + * @return the {@link Pure} instance + */ + public static Pure> pureChoice() { + return Choice3::c; + } + private static final class _A extends Choice3 { private final A a; @@ -296,6 +308,4 @@ public String toString() { '}'; } } - - } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index 4f79f3d5e..d6ce118b2 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple4; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.Functor; @@ -216,6 +217,18 @@ public static Choice4 d(D d) { return new _D<>(d); } + /** + * The canonical {@link Pure} instance for {@link Choice4}. + * + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @return the {@link Pure} instance + */ + public static Pure> pureChoice() { + return Choice4::d; + } + private static final class _A extends Choice4 { private final A a; diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index 8714e4395..593d31b83 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple5; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -241,6 +242,19 @@ public static Choice5 e(E e) { return new _E<>(e); } + /** + * The canonical {@link Pure} instance for {@link Choice5}. + * + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the fourth possible type + * @return the {@link Pure} instance + */ + public static Pure> pureChoice() { + return Choice5::e; + } + private static final class _A extends Choice5 { private final A a; diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index ff2ba8df5..7ca0c0082 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple6; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -268,6 +269,20 @@ public static Choice6 f(F f) { return new _F<>(f); } + /** + * The canonical {@link Pure} instance for {@link Choice6}. + * + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the fourth possible type + * @param the fifth possible type + * @return the {@link Pure} instance + */ + public static Pure> pureChoice() { + return Choice6::f; + } + private static final class _A extends Choice6 { private final A a; diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index 590796133..1118697bc 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple7; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -294,6 +295,21 @@ public static Choice7 g(G g) { return new _G<>(g); } + /** + * The canonical {@link Pure} instance for {@link Choice7}. + * + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the fourth possible type + * @param the fifth possible type + * @param the sixth possible type + * @return the {@link Pure} instance + */ + public static Pure> pureChoice() { + return Choice7::g; + } + private static final class _A extends Choice7 { private final A a; diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index cfdb71587..d0eb8a42b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple8; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -314,6 +315,21 @@ public static Choice8 h(H h) { return new _H<>(h); } + /** + * The canonical {@link Pure} instance for {@link Choice8}. + * + * @param the first possible type + * @param the second possible type + * @param the third possible type + * @param the fourth possible type + * @param the fifth possible type + * @param the sixth possible type + * @param the seventh possible type + * @return the {@link Pure} instance + */ + public static Pure> pureChoice() { + return Choice8::h; + } private static final class _A extends Choice8 { diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index 176745aba..15eb94dca 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.hlist.HList.HNil; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -26,48 +27,75 @@ public class SingletonHList<_1> extends HCons<_1, HNil> implements super(_1, nil()); } + /** + * {@inheritDoc} + */ @Override public <_0> Tuple2<_0, _1> cons(_0 _0) { return new Tuple2<>(_0, this); } + /** + * {@inheritDoc} + */ @Override public <_1Prime> SingletonHList<_1Prime> fmap(Fn1 fn) { return Monad.super.<_1Prime>fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_1Prime> SingletonHList<_1Prime> pure(_1Prime _1Prime) { return singletonHList(_1Prime); } + /** + * {@inheritDoc} + */ @Override public <_1Prime> SingletonHList<_1Prime> zip( Applicative, SingletonHList> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_1Prime> Lazy> lazyZip( Lazy, SingletonHList>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_1Prime, SingletonHList>::coerce); } + /** + * {@inheritDoc} + */ @Override public <_1Prime> SingletonHList<_1Prime> discardL(Applicative<_1Prime, SingletonHList> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_1Prime> SingletonHList<_1> discardR(Applicative<_1Prime, SingletonHList> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_1Prime> SingletonHList<_1Prime> flatMap(Fn1>> f) { return f.apply(head()).coerce(); } + /** + * {@inheritDoc} + */ @Override public , TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, @@ -85,4 +113,13 @@ AppTrav extends Applicative> AppTrav traverse(Fn1 R into(Fn1 fn) { return fn.apply(head()); } + + /** + * The canonical {@link Pure} instance for {@link SingletonHList}. + * + * @return the {@link Pure} instance + */ + public static Pure> pureSingletonHList() { + return HList::singletonHList; + } } 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 0cc52aefd..21fc30cfd 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 @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn1.Head; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -44,96 +45,150 @@ public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements _2 = tail.head(); } + /** + * {@inheritDoc} + */ @Override public <_0> Tuple3<_0, _1, _2> cons(_0 _0) { return new Tuple3<>(_0, this); } + /** + * {@inheritDoc} + */ @Override public _1 _1() { return _1; } + /** + * {@inheritDoc} + */ @Override public _2 _2() { return _2; } + /** + * {@inheritDoc} + */ @Override public _1 getKey() { return _1(); } + /** + * {@inheritDoc} + */ @Override public _2 getValue() { return _2(); } + /** + * {@inheritDoc} + */ @Override public _2 setValue(_2 value) { throw new UnsupportedOperationException(); } + /** + * {@inheritDoc} + */ @Override public Tuple2<_2, _1> invert() { return tuple(_2, _1); } + /** + * {@inheritDoc} + */ @Override public <_2Prime> Tuple2<_1, _2Prime> fmap(Fn1 fn) { return Monad.super.<_2Prime>fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_1Prime> Tuple2<_1Prime, _2> biMapL(Fn1 fn) { return (Tuple2<_1Prime, _2>) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_2Prime> Tuple2<_1, _2Prime> biMapR(Fn1 fn) { return (Tuple2<_1, _2Prime>) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public <_1Prime, _2Prime> Tuple2<_1Prime, _2Prime> biMap(Fn1 lFn, Fn1 rFn) { return new Tuple2<>(lFn.apply(_1()), tail().fmap(rFn)); } + /** + * {@inheritDoc} + */ @Override public <_2Prime> Tuple2<_1, _2Prime> pure(_2Prime _2Prime) { return tuple(_1, _2Prime); } + /** + * {@inheritDoc} + */ @Override public <_2Prime> Tuple2<_1, _2Prime> zip( Applicative, Tuple2<_1, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_2Prime> Lazy> lazyZip( Lazy, Tuple2<_1, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_2Prime, Tuple2<_1, ?>>::coerce); } + /** + * {@inheritDoc} + */ @Override public <_2Prime> Tuple2<_1, _2Prime> discardL(Applicative<_2Prime, Tuple2<_1, ?>> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_2Prime> Tuple2<_1, _2> discardR(Applicative<_2Prime, Tuple2<_1, ?>> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_2Prime> Tuple2<_1, _2Prime> flatMap(Fn1>> f) { return pure(f.apply(_2).>coerce()._2()); } + /** + * {@inheritDoc} + */ @Override public <_2Prime, App extends Applicative, TravB extends Traversable<_2Prime, Tuple2<_1, ?>>, AppTrav extends Applicative> AppTrav traverse( @@ -176,4 +231,20 @@ public static Tuple2 fill(A a) { public static Maybe> fromIterable(Iterable as) { return uncons(as).flatMap(tail -> tail.traverse(Head::head, Maybe::just)); } + + /** + * The canonical {@link Pure} instance for {@link Tuple2}. + * + * @param _1 the head element + * @param <_1> the head element type + * @return the {@link Pure} instance + */ + public static <_1> Pure> pureTuple(_1 _1) { + return new Pure>() { + @Override + public <_2> Tuple2<_1, _2> checkedApply(_2 _2) { + return tuple(_1, _2); + } + }; + } } 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 83ed9b54e..f0e91cfae 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 @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.product.Product3; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -44,98 +45,152 @@ public class Tuple3<_1, _2, _3> extends HCons<_1, Tuple2<_2, _3>> implements _3 = tail._2(); } + /** + * {@inheritDoc} + */ @Override public <_0> Tuple4<_0, _1, _2, _3> cons(_0 _0) { return new Tuple4<>(_0, this); } + /** + * {@inheritDoc} + */ @Override public _1 _1() { return _1; } + /** + * {@inheritDoc} + */ @Override public _2 _2() { return _2; } + /** + * {@inheritDoc} + */ @Override public _3 _3() { return _3; } + /** + * {@inheritDoc} + */ @Override public Tuple3<_2, _3, _1> rotateL3() { return tuple(_2, _3, _1); } + /** + * {@inheritDoc} + */ @Override public Tuple3<_3, _1, _2> rotateR3() { return tuple(_3, _1, _2); } + /** + * {@inheritDoc} + */ @Override public Tuple3<_2, _1, _3> invert() { return tuple(_2, _1, _3); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Fn1 fn) { return (Tuple3<_1, _2, _3Prime>) Monad.super.fmap(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_2Prime> Tuple3<_1, _2Prime, _3> biMapL(Fn1 fn) { return (Tuple3<_1, _2Prime, _3>) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_3Prime> Tuple3<_1, _2, _3Prime> biMapR(Fn1 fn) { return (Tuple3<_1, _2, _3Prime>) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public <_2Prime, _3Prime> Tuple3<_1, _2Prime, _3Prime> biMap(Fn1 lFn, Fn1 rFn) { return new Tuple3<>(_1(), tail().biMap(lFn, rFn)); } + /** + * {@inheritDoc} + */ @Override public <_3Prime> Tuple3<_1, _2, _3Prime> pure(_3Prime _3Prime) { return tuple(_1, _2, _3Prime); } + /** + * {@inheritDoc} + */ @Override public <_3Prime> Tuple3<_1, _2, _3Prime> zip( Applicative, Tuple3<_1, _2, ?>> appFn) { return biMapR(appFn.>>coerce()._3()::apply); } + /** + * {@inheritDoc} + */ @Override public <_3Prime> Lazy> lazyZip( Lazy, Tuple3<_1, _2, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_3Prime, Tuple3<_1, _2, ?>>::coerce); } + /** + * {@inheritDoc} + */ @Override public <_3Prime> Tuple3<_1, _2, _3Prime> discardL(Applicative<_3Prime, Tuple3<_1, _2, ?>> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_3Prime> Tuple3<_1, _2, _3> discardR(Applicative<_3Prime, Tuple3<_1, _2, ?>> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_3Prime> Tuple3<_1, _2, _3Prime> flatMap( Fn1>> f) { return pure(f.apply(_3).>coerce()._3); } + /** + * {@inheritDoc} + */ @Override public <_3Prime, App extends Applicative, TravB extends Traversable<_3Prime, Tuple3<_1, _2, ?>>, AppTrav extends Applicative> AppTrav traverse( @@ -167,4 +222,22 @@ public static Tuple3 fill(A a) { public static Maybe> fromIterable(Iterable as) { return uncons(as).flatMap(Into.into((head, tail) -> Tuple2.fromIterable(tail).fmap(t -> t.cons(head)))); } + + /** + * The canonical {@link Pure} instance for {@link Tuple3}. + * + * @param _1 the head element + * @param _2 the second element + * @param <_1> the head element type + * @param <_2> the second element type + * @return the {@link Pure} instance + */ + public static <_1, _2> Pure> pureTuple(_1 _1, _2 _2) { + return new Pure>() { + @Override + public <_3> Tuple3<_1, _2, _3> checkedApply(_3 _3) throws Throwable { + return tuple(_1, _2, _3); + } + }; + } } 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 3f6ebe443..a629fa737 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 @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.product.Product4; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -47,110 +48,173 @@ public class Tuple4<_1, _2, _3, _4> extends HCons<_1, Tuple3<_2, _3, _4>> implem _4 = tail._3(); } + /** + * {@inheritDoc} + */ @Override public <_0> Tuple5<_0, _1, _2, _3, _4> cons(_0 _0) { return new Tuple5<>(_0, this); } + /** + * {@inheritDoc} + */ @Override public _1 _1() { return _1; } + /** + * {@inheritDoc} + */ @Override public _2 _2() { return _2; } + /** + * {@inheritDoc} + */ @Override public _3 _3() { return _3; } + /** + * {@inheritDoc} + */ @Override public _4 _4() { return _4; } + /** + * {@inheritDoc} + */ @Override public Tuple4<_2, _3, _4, _1> rotateL4() { return tuple(_2, _3, _4, _1); } + /** + * {@inheritDoc} + */ @Override public Tuple4<_4, _1, _2, _3> rotateR4() { return tuple(_4, _1, _2, _3); } + /** + * {@inheritDoc} + */ @Override public Tuple4<_2, _3, _1, _4> rotateL3() { return tuple(_2, _3, _1, _4); } + /** + * {@inheritDoc} + */ @Override public Tuple4<_3, _1, _2, _4> rotateR3() { return tuple(_3, _1, _2, _4); } + /** + * {@inheritDoc} + */ @Override public Tuple4<_2, _1, _3, _4> invert() { return tuple(_2, _1, _3, _4); } + /** + * {@inheritDoc} + */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(Fn1 fn) { return (Tuple4<_1, _2, _3, _4Prime>) Monad.super.<_4Prime>fmap(fn); } + /** + * {@inheritDoc} + */ @Override public <_3Prime> Tuple4<_1, _2, _3Prime, _4> biMapL(Fn1 fn) { return (Tuple4<_1, _2, _3Prime, _4>) Bifunctor.super.<_3Prime>biMapL(fn); } + /** + * {@inheritDoc} + */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> biMapR(Fn1 fn) { return (Tuple4<_1, _2, _3, _4Prime>) Bifunctor.super.<_4Prime>biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public <_3Prime, _4Prime> Tuple4<_1, _2, _3Prime, _4Prime> biMap(Fn1 lFn, Fn1 rFn) { return new Tuple4<>(_1(), tail().biMap(lFn, rFn)); } + /** + * {@inheritDoc} + */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> pure(_4Prime _4Prime) { return tuple(_1, _2, _3, _4Prime); } + /** + * {@inheritDoc} + */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> zip( Applicative, Tuple4<_1, _2, _3, ?>> appFn) { return biMapR(appFn.>>coerce()._4()::apply); } + /** + * {@inheritDoc} + */ @Override public <_4Prime> Lazy> lazyZip( Lazy, Tuple4<_1, _2, _3, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_4Prime, Tuple4<_1, _2, _3, ?>>::coerce); } + /** + * {@inheritDoc} + */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> discardL(Applicative<_4Prime, Tuple4<_1, _2, _3, ?>> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4> discardR(Applicative<_4Prime, Tuple4<_1, _2, _3, ?>> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> flatMap( Fn1>> f) { return pure(f.apply(_4).>coerce()._4); } + /** + * {@inheritDoc} + */ @Override public <_4Prime, App extends Applicative, TravB extends Traversable<_4Prime, Tuple4<_1, _2, _3, ?>>, AppTrav extends Applicative> AppTrav traverse( @@ -182,4 +246,24 @@ public static Tuple4 fill(A a) { public static Maybe> fromIterable(Iterable as) { return uncons(as).flatMap(Into.into((head, tail) -> Tuple3.fromIterable(tail).fmap(t -> t.cons(head)))); } + + /** + * The canonical {@link Pure} instance for {@link Tuple4}. + * + * @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 {@link Pure} instance + */ + public static <_1, _2, _3> Pure> pureTuple(_1 _1, _2 _2, _3 _3) { + return new Pure>() { + @Override + public <_4> Tuple4<_1, _2, _3, _4> checkedApply(_4 _4) throws Throwable { + return tuple(_1, _2, _3, _4); + } + }; + } } 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 c945b6b0b..53595a42c 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 @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.product.Product5; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -50,127 +51,199 @@ public class Tuple5<_1, _2, _3, _4, _5> extends HCons<_1, Tuple4<_2, _3, _4, _5> _5 = tail._4(); } + /** + * {@inheritDoc} + */ @Override public <_0> Tuple6<_0, _1, _2, _3, _4, _5> cons(_0 _0) { return new Tuple6<>(_0, this); } + /** + * {@inheritDoc} + */ @Override public _1 _1() { return _1; } + /** + * {@inheritDoc} + */ @Override public _2 _2() { return _2; } + /** + * {@inheritDoc} + */ @Override public _3 _3() { return _3; } + /** + * {@inheritDoc} + */ @Override public _4 _4() { return _4; } + /** + * {@inheritDoc} + */ @Override public _5 _5() { return _5; } + /** + * {@inheritDoc} + */ @Override public Tuple5<_2, _3, _4, _5, _1> rotateL5() { return tuple(_2, _3, _4, _5, _1); } + /** + * {@inheritDoc} + */ @Override public Tuple5<_5, _1, _2, _3, _4> rotateR5() { return tuple(_5, _1, _2, _3, _4); } + /** + * {@inheritDoc} + */ @Override public Tuple5<_2, _3, _4, _1, _5> rotateL4() { return tuple(_2, _3, _4, _1, _5); } + /** + * {@inheritDoc} + */ @Override public Tuple5<_4, _1, _2, _3, _5> rotateR4() { return tuple(_4, _1, _2, _3, _5); } + /** + * {@inheritDoc} + */ @Override public Tuple5<_2, _3, _1, _4, _5> rotateL3() { return tuple(_2, _3, _1, _4, _5); } + /** + * {@inheritDoc} + */ @Override public Tuple5<_3, _1, _2, _4, _5> rotateR3() { return tuple(_3, _1, _2, _4, _5); } + /** + * {@inheritDoc} + */ @Override public Tuple5<_2, _1, _3, _4, _5> invert() { return tuple(_2, _1, _3, _4, _5); } + /** + * {@inheritDoc} + */ @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Fn1 fn) { return Monad.super.<_5Prime>fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_4Prime> Tuple5<_1, _2, _3, _4Prime, _5> biMapL(Fn1 fn) { return (Tuple5<_1, _2, _3, _4Prime, _5>) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> biMapR(Fn1 fn) { return (Tuple5<_1, _2, _3, _4, _5Prime>) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public <_4Prime, _5Prime> Tuple5<_1, _2, _3, _4Prime, _5Prime> biMap(Fn1 lFn, Fn1 rFn) { return new Tuple5<>(_1(), tail().biMap(lFn, rFn)); } + /** + * {@inheritDoc} + */ @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> pure(_5Prime _5Prime) { return tuple(_1, _2, _3, _4, _5Prime); } + /** + * {@inheritDoc} + */ @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> zip( Applicative, Tuple5<_1, _2, _3, _4, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_5Prime> Lazy> lazyZip( Lazy, Tuple5<_1, _2, _3, _4, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_5Prime, Tuple5<_1, _2, _3, _4, ?>>::coerce); } + /** + * {@inheritDoc} + */ @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> discardL(Applicative<_5Prime, Tuple5<_1, _2, _3, _4, ?>> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5> discardR(Applicative<_5Prime, Tuple5<_1, _2, _3, _4, ?>> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> flatMap( Fn1>> f) { return pure(f.apply(_5).>coerce()._5()); } + /** + * {@inheritDoc} + */ @Override public <_5Prime, App extends Applicative, TravB extends Traversable<_5Prime, Tuple5<_1, _2, _3, _4, ?>>, AppTrav extends Applicative> AppTrav traverse( @@ -202,4 +275,26 @@ public static Tuple5 fill(A a) { public static Maybe> fromIterable(Iterable as) { return uncons(as).flatMap(Into.into((head, tail) -> Tuple4.fromIterable(tail).fmap(t -> t.cons(head)))); } + + /** + * The canonical {@link Pure} instance for {@link Tuple5}. + * + * @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 {@link Pure} instance + */ + public static <_1, _2, _3, _4> Pure> pureTuple(_1 _1, _2 _2, _3 _3, _4 _4) { + return new Pure>() { + @Override + public <_5> Tuple5<_1, _2, _3, _4, _5> checkedApply(_5 _5) throws Throwable { + return tuple(_1, _2, _3, _4, _5); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 55e71e14a..3e33d97bb 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.product.Product6; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -54,103 +55,163 @@ public class Tuple6<_1, _2, _3, _4, _5, _6> extends HCons<_1, Tuple5<_2, _3, _4, _6 = tail._5(); } + /** + * {@inheritDoc} + */ @Override public <_0> Tuple7<_0, _1, _2, _3, _4, _5, _6> cons(_0 _0) { return new Tuple7<>(_0, this); } + /** + * {@inheritDoc} + */ @Override public _1 _1() { return _1; } + /** + * {@inheritDoc} + */ @Override public _2 _2() { return _2; } + /** + * {@inheritDoc} + */ @Override public _3 _3() { return _3; } + /** + * {@inheritDoc} + */ @Override public _4 _4() { return _4; } + /** + * {@inheritDoc} + */ @Override public _5 _5() { return _5; } + /** + * {@inheritDoc} + */ @Override public _6 _6() { return _6; } + /** + * {@inheritDoc} + */ @Override public Tuple6<_2, _3, _4, _5, _6, _1> rotateL6() { return tuple(_2, _3, _4, _5, _6, _1); } + /** + * {@inheritDoc} + */ @Override public Tuple6<_6, _1, _2, _3, _4, _5> rotateR6() { return tuple(_6, _1, _2, _3, _4, _5); } + /** + * {@inheritDoc} + */ @Override public Tuple6<_2, _3, _4, _5, _1, _6> rotateL5() { return tuple(_2, _3, _4, _5, _1, _6); } + /** + * {@inheritDoc} + */ @Override public Tuple6<_5, _1, _2, _3, _4, _6> rotateR5() { return tuple(_5, _1, _2, _3, _4, _6); } + /** + * {@inheritDoc} + */ @Override public Tuple6<_2, _3, _4, _1, _5, _6> rotateL4() { return tuple(_2, _3, _4, _1, _5, _6); } + /** + * {@inheritDoc} + */ @Override public Tuple6<_4, _1, _2, _3, _5, _6> rotateR4() { return tuple(_4, _1, _2, _3, _5, _6); } + /** + * {@inheritDoc} + */ @Override public Tuple6<_2, _3, _1, _4, _5, _6> rotateL3() { return tuple(_2, _3, _1, _4, _5, _6); } + /** + * {@inheritDoc} + */ @Override public Tuple6<_3, _1, _2, _4, _5, _6> rotateR3() { return tuple(_3, _1, _2, _4, _5, _6); } + /** + * {@inheritDoc} + */ @Override public Tuple6<_2, _1, _3, _4, _5, _6> invert() { return tuple(_2, _1, _3, _4, _5, _6); } + /** + * {@inheritDoc} + */ @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> fmap(Fn1 fn) { return Monad.super.<_6Prime>fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_5Prime> Tuple6<_1, _2, _3, _4, _5Prime, _6> biMapL(Fn1 fn) { return (Tuple6<_1, _2, _3, _4, _5Prime, _6>) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> biMapR(Fn1 fn) { return (Tuple6<_1, _2, _3, _4, _5, _6Prime>) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public <_5Prime, _6Prime> Tuple6<_1, _2, _3, _4, _5Prime, _6Prime> biMap( Fn1 lFn, @@ -158,40 +219,61 @@ public <_5Prime, _6Prime> Tuple6<_1, _2, _3, _4, _5Prime, _6Prime> biMap( return new Tuple6<>(_1(), tail().biMap(lFn, rFn)); } + /** + * {@inheritDoc} + */ @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> pure(_6Prime _6Prime) { return tuple(_1, _2, _3, _4, _5, _6Prime); } + /** + * {@inheritDoc} + */ @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> zip( Applicative, Tuple6<_1, _2, _3, _4, _5, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_6Prime> Lazy> lazyZip( Lazy, Tuple6<_1, _2, _3, _4, _5, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>::coerce); } + /** + * {@inheritDoc} + */ @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> discardL( Applicative<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6> discardR(Applicative<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> flatMap( Fn1>> f) { return pure(f.apply(_6).>coerce()._6()); } + /** + * {@inheritDoc} + */ @Override public <_6Prime, App extends Applicative, TravB extends Traversable<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>, AppTrav extends Applicative> AppTrav traverse( @@ -223,4 +305,29 @@ public static Tuple6 fill(A a) { public static Maybe> fromIterable(Iterable as) { return uncons(as).flatMap(Into.into((head, tail) -> Tuple5.fromIterable(tail).fmap(t -> t.cons(head)))); } + + /** + * The canonical {@link Pure} instance for {@link Tuple6}. + * + * @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 {@link Pure} instance + */ + public static <_1, _2, _3, _4, _5> Pure> pureTuple(_1 _1, _2 _2, _3 _3, _4 _4, + _5 _5) { + return new Pure>() { + @Override + public <_6> Tuple6<_1, _2, _3, _4, _5, _6> checkedApply(_6 _6) { + return tuple(_1, _2, _3, _4, _5, _6); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index 2de78379c..f352b5438 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.product.Product7; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -58,118 +59,187 @@ public class Tuple7<_1, _2, _3, _4, _5, _6, _7> extends HCons<_1, Tuple6<_2, _3, _7 = tail._6(); } + /** + * {@inheritDoc} + */ @Override public <_0> Tuple8<_0, _1, _2, _3, _4, _5, _6, _7> cons(_0 _0) { return new Tuple8<>(_0, this); } + /** + * {@inheritDoc} + */ @Override public _1 _1() { return _1; } + /** + * {@inheritDoc} + */ @Override public _2 _2() { return _2; } + /** + * {@inheritDoc} + */ @Override public _3 _3() { return _3; } + /** + * {@inheritDoc} + */ @Override public _4 _4() { return _4; } + /** + * {@inheritDoc} + */ @Override public _5 _5() { return _5; } + /** + * {@inheritDoc} + */ @Override public _6 _6() { return _6; } + /** + * {@inheritDoc} + */ @Override public _7 _7() { return _7; } + /** + * {@inheritDoc} + */ @Override public Tuple7<_2, _3, _4, _5, _6, _7, _1> rotateL7() { return tuple(_2, _3, _4, _5, _6, _7, _1); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_7, _1, _2, _3, _4, _5, _6> rotateR7() { return tuple(_7, _1, _2, _3, _4, _5, _6); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_2, _3, _4, _5, _6, _1, _7> rotateL6() { return tuple(_2, _3, _4, _5, _6, _1, _7); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_6, _1, _2, _3, _4, _5, _7> rotateR6() { return tuple(_6, _1, _2, _3, _4, _5, _7); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_2, _3, _4, _5, _1, _6, _7> rotateL5() { return tuple(_2, _3, _4, _5, _1, _6, _7); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_5, _1, _2, _3, _4, _6, _7> rotateR5() { return tuple(_5, _1, _2, _3, _4, _6, _7); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_2, _3, _4, _1, _5, _6, _7> rotateL4() { return tuple(_2, _3, _4, _1, _5, _6, _7); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_4, _1, _2, _3, _5, _6, _7> rotateR4() { return tuple(_4, _1, _2, _3, _5, _6, _7); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_2, _3, _1, _4, _5, _6, _7> rotateL3() { return tuple(_2, _3, _1, _4, _5, _6, _7); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_3, _1, _2, _4, _5, _6, _7> rotateR3() { return tuple(_3, _1, _2, _4, _5, _6, _7); } + /** + * {@inheritDoc} + */ @Override public Tuple7<_2, _1, _3, _4, _5, _6, _7> invert() { return tuple(_2, _1, _3, _4, _5, _6, _7); } + /** + * {@inheritDoc} + */ @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> fmap(Fn1 fn) { return Monad.super.<_7Prime>fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_6Prime> Tuple7<_1, _2, _3, _4, _5, _6Prime, _7> biMapL(Fn1 fn) { return (Tuple7<_1, _2, _3, _4, _5, _6Prime, _7>) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> biMapR(Fn1 fn) { return (Tuple7<_1, _2, _3, _4, _5, _6, _7Prime>) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public <_6Prime, _7Prime> Tuple7<_1, _2, _3, _4, _5, _6Prime, _7Prime> biMap( Fn1 lFn, @@ -177,41 +247,62 @@ public <_6Prime, _7Prime> Tuple7<_1, _2, _3, _4, _5, _6Prime, _7Prime> biMap( return new Tuple7<>(_1(), tail().biMap(lFn, rFn)); } + /** + * {@inheritDoc} + */ @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> pure(_7Prime _7Prime) { return tuple(_1, _2, _3, _4, _5, _6, _7Prime); } + /** + * {@inheritDoc} + */ @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> zip( Applicative, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_7Prime> Lazy> lazyZip( Lazy, Tuple7<_1, _2, _3, _4, _5, _6, ?>>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>::coerce); } + /** + * {@inheritDoc} + */ @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> discardL( Applicative<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7> discardR( Applicative<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> flatMap( Fn1>> f) { return pure(f.apply(_7).>coerce()._7()); } + /** + * {@inheritDoc} + */ @Override public <_7Prime, App extends Applicative, TravB extends Traversable<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, @@ -244,4 +335,31 @@ public static Tuple7 fill(A a) { public static Maybe> fromIterable(Iterable as) { return uncons(as).flatMap(Into.into((head, tail) -> Tuple6.fromIterable(tail).fmap(t -> t.cons(head)))); } + + /** + * The canonical {@link Pure} instance for {@link Tuple7}. + * + * @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 _6 the sixth 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 + * @param <_6> the sixth element type + * @return the {@link Pure} instance + */ + public static <_1, _2, _3, _4, _5, _6> Pure> pureTuple(_1 _1, _2 _2, _3 _3, _4 _4, + _5 _5, _6 _6) { + return new Pure>() { + @Override + public <_7> Tuple7<_1, _2, _3, _4, _5, _6, _7> checkedApply(_7 _7) throws Throwable { + return tuple(_1, _2, _3, _4, _5, _6, _7); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 898124fa8..1287b275e 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.product.Product8; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -62,133 +63,211 @@ public class Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> extends HCons<_1, Tuple7<_2, _8 = tail._7(); } + /** + * {@inheritDoc} + */ @Override public <_0> HCons<_0, Tuple8<_1, _2, _3, _4, _5, _6, _7, _8>> cons(_0 _0) { return new HCons<>(_0, this); } + /** + * {@inheritDoc} + */ @Override public _1 _1() { return _1; } + /** + * {@inheritDoc} + */ @Override public _2 _2() { return _2; } + /** + * {@inheritDoc} + */ @Override public _3 _3() { return _3; } + /** + * {@inheritDoc} + */ @Override public _4 _4() { return _4; } + /** + * {@inheritDoc} + */ @Override public _5 _5() { return _5; } + /** + * {@inheritDoc} + */ @Override public _6 _6() { return _6; } + /** + * {@inheritDoc} + */ @Override public _7 _7() { return _7; } + /** + * {@inheritDoc} + */ @Override public _8 _8() { return _8; } + /** + * {@inheritDoc} + */ @Override public Tuple8<_2, _3, _4, _5, _6, _7, _8, _1> rotateL8() { return tuple(_2, _3, _4, _5, _6, _7, _8, _1); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_8, _1, _2, _3, _4, _5, _6, _7> rotateR8() { return tuple(_8, _1, _2, _3, _4, _5, _6, _7); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_2, _3, _4, _5, _6, _7, _1, _8> rotateL7() { return tuple(_2, _3, _4, _5, _6, _7, _1, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_7, _1, _2, _3, _4, _5, _6, _8> rotateR7() { return tuple(_7, _1, _2, _3, _4, _5, _6, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_2, _3, _4, _5, _6, _1, _7, _8> rotateL6() { return tuple(_2, _3, _4, _5, _6, _1, _7, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_6, _1, _2, _3, _4, _5, _7, _8> rotateR6() { return tuple(_6, _1, _2, _3, _4, _5, _7, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_2, _3, _4, _5, _1, _6, _7, _8> rotateL5() { return tuple(_2, _3, _4, _5, _1, _6, _7, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_5, _1, _2, _3, _4, _6, _7, _8> rotateR5() { return tuple(_5, _1, _2, _3, _4, _6, _7, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_2, _3, _4, _1, _5, _6, _7, _8> rotateL4() { return tuple(_2, _3, _4, _1, _5, _6, _7, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_4, _1, _2, _3, _5, _6, _7, _8> rotateR4() { return tuple(_4, _1, _2, _3, _5, _6, _7, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_2, _3, _1, _4, _5, _6, _7, _8> rotateL3() { return tuple(_2, _3, _1, _4, _5, _6, _7, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_3, _1, _2, _4, _5, _6, _7, _8> rotateR3() { return tuple(_3, _1, _2, _4, _5, _6, _7, _8); } + /** + * {@inheritDoc} + */ @Override public Tuple8<_2, _1, _3, _4, _5, _6, _7, _8> invert() { return tuple(_2, _1, _3, _4, _5, _6, _7, _8); } + /** + * {@inheritDoc} + */ @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> fmap(Fn1 fn) { return Monad.super.<_8Prime>fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_7Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8> biMapL(Fn1 fn) { return (Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8>) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> biMapR(Fn1 fn) { return (Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime>) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public <_7Prime, _8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8Prime> biMap( Fn1 lFn, @@ -196,17 +275,26 @@ public <_7Prime, _8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8Prime> biMap return new Tuple8<>(_1(), tail().biMap(lFn, rFn)); } + /** + * {@inheritDoc} + */ @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> pure(_8Prime _8Prime) { return tuple(_1, _2, _3, _4, _5, _6, _7, _8Prime); } + /** + * {@inheritDoc} + */ @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> zip( Applicative, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_8Prime> Lazy> lazyZip( Lazy, @@ -214,24 +302,36 @@ public <_8Prime> Lazy> lazyZip( return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>::coerce); } + /** + * {@inheritDoc} + */ @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> discardL( Applicative<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> discardR( Applicative<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> flatMap( Fn1>> f) { return pure(f.apply(_8).>coerce()._8()); } + /** + * {@inheritDoc} + */ @Override public <_8Prime, App extends Applicative, TravB extends Traversable<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, @@ -264,4 +364,36 @@ public static Tuple8 fill(A a) { public static Maybe> fromIterable(Iterable as) { return uncons(as).flatMap(Into.into((head, tail) -> Tuple7.fromIterable(tail).fmap(t -> t.cons(head)))); } + + /** + * The canonical {@link Pure} instance for {@link Tuple8}. + * + * @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 _6 the sixth element + * @param _7 the seventh 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 + * @param <_6> the sixth element type + * @param <_7> the seventh element type + * @return the {@link Pure} instance + */ + public static <_1, _2, _3, _4, _5, _6, _7> Pure> pureTuple(_1 _1, _2 _2, + _3 _3, _4 _4, + _5 _5, _6 _6, + _7 _7) { + return new Pure>() { + @Override + public <_8> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> checkedApply(_8 _8) throws Throwable { + return tuple(_1, _2, _3, _4, _5, _6, _7, _8); + } + }; + } + } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index d08195f42..869f1290e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -3,6 +3,8 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.builtin.fn1.Constantly; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cartesian; import com.jnape.palatable.lambda.functor.Cocartesian; @@ -284,4 +286,13 @@ static Fn1 fn1(Fn1 fn) { static Fn1 fromFunction(Function function) { return function::apply; } + + /** + * The canonical {@link Pure} instance for {@link Fn1}. + * + * @return the {@link Pure} instance + */ + static Pure> pureFn1() { + return Constantly::constantly; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java index c21c62908..a9f339db9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -18,7 +19,11 @@ * @param the recursive function's output type * @see Trampoline */ -public abstract class RecursiveResult implements CoProduct2>, Bifunctor>, Monad>, Traversable> { +public abstract class RecursiveResult implements + CoProduct2>, + Bifunctor>, + Monad>, + Traversable> { private RecursiveResult() { } @@ -92,6 +97,16 @@ public static RecursiveResult terminate(B b) { return new Terminate<>(b); } + /** + * The canonical {@link Pure} instance for {@link RecursiveResult}. + * + * @param the recursive function's input type + * @return the {@link Pure} instance + */ + public static Pure> pureRecursiveResult() { + return RecursiveResult::terminate; + } + static final class Recurse extends RecursiveResult { final A a; diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index a9a50eb91..94f78d9cf 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import java.util.Objects; @@ -102,4 +103,19 @@ public int hashCode() { public String toString() { return "Compose{fga=" + fga + '}'; } + + /** + * The canonical {@link Pure} instance for {@link Compose}. + * + * @return the {@link Pure} instance + */ + public static , G extends Applicative> Pure> pureCompose( + Pure pureF, Pure pureG) { + return new Pure>() { + @Override + public Compose checkedApply(A a) throws Throwable { + return new Compose<>(pureF., Applicative, F>>apply(pureG.apply(a))); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index 73e974ede..0ce465235 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; @@ -50,6 +51,9 @@ public Const fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public Const pure(C c) { @@ -150,4 +154,20 @@ public String toString() { "a=" + a + '}'; } + + /** + * The canonical {@link Pure} instance for {@link Const}. + * + * @param a the stored value + * @param the left parameter type, and the type of the stored value + * @return the {@link Pure} instance + */ + public static Pure> pureConst(A a) { + return new Pure>() { + @Override + public Const checkedApply(B b) { + return new Const<>(a); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java index dba617294..0a48147cb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -113,4 +114,13 @@ public String toString() { "a=" + a + '}'; } + + /** + * The canonical {@link Pure} instance for {@link Identity}. + * + * @return the {@link Pure} instance + */ + public static Pure> pureIdentity() { + return Identity::new; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java index fff6acc72..103ddb7ff 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.traversable.Traversable; @@ -132,6 +133,15 @@ public static Lazy lazy(Fn0 fn0) { return new Later<>(fn0); } + /** + * The canonical {@link Pure} instance for {@link Lazy}. + * + * @return the {@link Pure} instance + */ + public static Pure> pureLazy() { + return Lazy::lazy; + } + private static final class Later extends Lazy { private final Fn0 fn0; diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java index f1a4b3243..6512abf65 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cocartesian; import com.jnape.palatable.lambda.monad.Monad; @@ -131,4 +132,21 @@ public Market diMapR(Fn1 fn) { public Market contraMap(Fn1 fn) { return (Market) Cocartesian.super.contraMap(fn); } + + /** + * The canonical {@link Pure} instance for {@link Market}. + * + * @param the output that might fail to be produced + * @param the input that guarantees its output + * @param the input that might fail to map to its output + * @return the {@link Pure} instance + */ + public static Pure> pureMarket() { + return new Pure>() { + @Override + public Market checkedApply(T t) { + return new Market<>(constantly(t), constantly(left(t))); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java index ed3f17470..9a2c36ddc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; @@ -210,4 +211,19 @@ public static State state(Fn1> public static State state(A a) { return gets(constantly(a)); } + + /** + * The canonical {@link Pure} instance for {@link State}. + * + * @param the state type + * @return the {@link Pure} instance + */ + public static Pure> pureState() { + return new Pure>() { + @Override + public State checkedApply(A a) throws Throwable { + return state(s -> tuple(a, s)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java index c601e6d65..24987beb8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java @@ -2,9 +2,14 @@ import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Downcast; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cocartesian; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.traversable.Traversable; + +import java.util.Objects; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; @@ -15,7 +20,11 @@ * @param the phantom type * @param the value type */ -public final class Tagged implements Monad>, Cocartesian> { +public final class Tagged implements + Monad>, + Traversable>, + Cocartesian> { + private final B b; public Tagged(B b) { @@ -79,6 +88,18 @@ public Tagged discardR(Applicative> appB) { return Monad.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public , TravC extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { + return fn.apply(b) + .fmap(c -> Downcast.>>downcast(new Tagged<>(c))) + .coerce(); + } + /** * {@inheritDoc} */ @@ -118,4 +139,29 @@ public Tagged diMapR(Fn1 fn) { public Tagged contraMap(Fn1 fn) { return (Tagged) Cocartesian.super.contraMap(fn); } + + @Override + public boolean equals(Object other) { + return other instanceof Tagged && Objects.equals(b, ((Tagged) other).b); + } + + @Override + public int hashCode() { + return Objects.hash(b); + } + + @Override + public String toString() { + return "Tagged{b=" + b + '}'; + } + + /** + * The canonical {@link Pure} instance for {@link Tagged}. + * + * @param the phantom type + * @return the {@link Pure} instance + */ + public static Pure> pureTagged() { + return Tagged::new; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index 00f4faf8f..fe5eeb7b4 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -7,9 +7,12 @@ import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.LazyRec; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.functor.builtin.State; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadError; @@ -20,6 +23,7 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; @@ -394,6 +398,15 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { }; } + /** + * The canonical {@link Pure} instance for {@link IO}. + * + * @return the {@link Pure} instance + */ + public static Pure> pureIO() { + return IO::io; + } + private static final class Compose extends IO { private final IO source; diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java index f3f26adba..7866eda32 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Compose; @@ -156,4 +157,21 @@ public String toString() { public static , L, R> EitherT eitherT(Monad, M> melr) { return new EitherT<>(melr); } + + /** + * The canonical {@link Pure} instance for {@link EitherT}. + * + * @param pureM the argument {@link Monad} {@link Pure} + * @param the argument {@link Monad} witness + * @param the left type + * @return the {@link Pure} instance + */ + public static , L> Pure> pureEitherT(Pure pureM) { + return new Pure>() { + @Override + public EitherT checkedApply(R r) throws Throwable { + return eitherT(pureM.>apply(r).fmap(Either::right)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java index 16bf78db5..d800b539c 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Identity; @@ -121,4 +122,20 @@ public String toString() { public static , A> IdentityT identityT(Monad, M> mia) { return new IdentityT<>(mia); } + + /** + * The canonical {@link Pure} instance for {@link IdentityT}. + * + * @param pureM the argument {@link Monad} {@link Pure} + * @param the argument {@link Monad} witness + * @return the {@link Pure} instance + */ + public static > Pure> pureIdentityT(Pure pureM) { + return new Pure>() { + @Override + public IdentityT checkedApply(A a) { + return identityT(pureM.>apply(a).fmap(Identity::new)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java index 512118edc..2cd3661ea 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Compose; @@ -124,4 +125,20 @@ public String toString() { public static , A> LazyT lazyT(Monad, M> mla) { return new LazyT<>(mla); } + + /** + * The canonical {@link Pure} instance for {@link LazyT}. + * + * @param pureM the argument {@link Monad} {@link Pure} + * @param the argument {@link Monad} witness + * @return the {@link Pure} instance + */ + public static > Pure> pureLazyT(Pure pureM) { + return new Pure>() { + @Override + public LazyT checkedApply(A a) { + return lazyT(pureM.>apply(a).fmap(Lazy::lazy)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index 09938d01e..57cc831ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -128,4 +129,20 @@ public String toString() { public static , A> MaybeT maybeT(Monad, M> mma) { return new MaybeT<>(mma); } + + /** + * The canonical {@link Pure} instance for {@link MaybeT}. + * + * @param pureM the argument {@link Monad} {@link Pure} + * @param the argument {@link Monad} witness + * @return the {@link Pure} instance + */ + public static > Pure> pureMaybeT(Pure pureM) { + return new Pure>() { + @Override + public MaybeT checkedApply(A a) { + return maybeT(pureM.>apply(a).fmap(Maybe::just)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index acda7e825..227bd1df2 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cartesian; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -178,4 +179,21 @@ public ReaderT> carry() { public static , A> ReaderT readerT(Fn1> fn) { return new ReaderT<>(fn); } + + /** + * The canonical {@link Pure} instance for {@link ReaderT}. + * + * @param pureM the argument {@link Monad} {@link Pure} + * @param the input type + * @param the argument {@link Monad} witness + * @return the {@link Pure} instance + */ + public static > Pure> pureReaderT(Pure pureM) { + return new Pure>() { + @Override + public ReaderT checkedApply(A a) { + return readerT(__ -> pureM.apply(a)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java index feb59212c..9aaba84f9 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; @@ -14,6 +15,7 @@ import com.jnape.palatable.lambda.optics.functions.View; import static com.jnape.palatable.lambda.functions.Fn1.fn1; +import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.optics.Iso.Simple.adapt; @@ -136,12 +138,11 @@ default Iso discardR(Applicative> appB) { */ @Override default Iso flatMap(Fn1>> fn) { - //noinspection RedundantTypeArguments - return unIso().fmap(bt -> Fn2.curried( - fn1(bt.fmap(fn.>fmap(Monad>::coerce)) - .fmap(Iso::unIso) - .fmap(Tuple2::_2) - .fmap(Fn1::fn1)))) + return unIso() + .>fmap(bt -> curried(fn1(bt.fmap(fn.>fmap(Monad::coerce)) + .fmap(Iso::unIso) + .fmap(Tuple2::_2) + .fmap(Fn1::fn1)))) .fmap(Fn2::uncurry) .fmap(bbu -> bbu.diMapL(Tuple2::fill)) .into(Iso::iso); @@ -279,6 +280,24 @@ static Iso.Simple simpleIso(Fn1 f, Fn1 the larger type for focusing + * @param the smaller type for focusing + * @param the smaller type for mirrored focusing + * @return the {@link Pure} instance + */ + static Pure> pureIso(Fn1 sa) { + return new Pure>() { + @Override + public Iso checkedApply(T t) { + return iso(sa, constantly(t)); + } + }; + } + /** * A convenience type with a simplified type signature for common isos with both unified "larger" values and * unified "smaller" values. diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java index 9f5cbc7f9..0d3297c2d 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Both; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cartesian; import com.jnape.palatable.lambda.functor.Functor; @@ -377,6 +378,20 @@ static Lens.Simple> both(Lens.Simple f, Lens.Sim return adapt(both((Lens) f, g)); } + /** + * The canonical {@link Pure} instance for {@link Lens}. + * + * @return the {@link Pure} instance + */ + static Pure> pureLens(Fn1 sa) { + return new Pure>() { + @Override + public Lens checkedApply(T t) { + return lens(sa, (s, b) -> t); + } + }; + } + /** * A convenience type with a simplified type signature for common lenses with both unified "larger" values and * unified "smaller" values. diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java index c76161413..16b81f23d 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -144,9 +144,11 @@ default Prism pure(U u) { */ @Override default Prism flatMap(Fn1>> f) { - return unPrism().into((bt, seta) -> prism( - s -> seta.apply(s).match(t -> matching(f.apply(t).>coerce(), s), Either::right), - b -> View.view(re(f.apply(bt.apply(b)).coerce())).apply(b))); + return unPrism() + .into((bt, seta) -> Prism.prism( + s -> seta.apply(s).>match(t -> matching(f.apply(t).>coerce(), s), + Either::right), + b -> View.view(re(f.apply(bt.apply(b)).coerce())).apply(b))); } /** @@ -328,6 +330,20 @@ static Prism fromPartial(Fn1 parti return prism(partialSa.diMap(downcast(), upcast()).choose(), bs); } + /** + * The canonical {@link Pure} instance for {@link Prism}. + * + * @return the {@link Pure} instance + */ + static Pure> purePrism() { + return new Pure>() { + @Override + public Prism checkedApply(T t) throws Throwable { + return prism(constantly(left(t)), constantly(t)); + } + }; + } + /** * A convenience type with a simplified type signature for common {@link Prism prism} with unified S/T * and A/B types. 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 6fe5f4a38..379b40234 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn1.Empty; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -164,4 +165,18 @@ public static LambdaIterable wrap(Iterable as) { public static LambdaIterable empty() { return wrap(emptyList()); } + + /** + * The canonical {@link Pure} instance for {@link LambdaIterable}. + * + * @return the {@link Pure} instance + */ + public static Pure> pureLambdaIterable() { + return new Pure>() { + @Override + public LambdaIterable checkedApply(A a) throws Throwable { + return wrap(singleton(a)); + } + }; + } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java index 8de5be33e..958140086 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java @@ -239,4 +239,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Either either = Either.pureEither().apply(1); + assertEquals(right(1), either); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java index ba02cadc7..5d3d65763 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java @@ -19,6 +19,7 @@ import static com.jnape.palatable.lambda.adt.Either.right; 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.Maybe.pureMaybe; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -147,4 +148,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Maybe maybe = pureMaybe().apply(1); + assertEquals(just(1), maybe); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java index 795054a87..be958203e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java @@ -17,7 +17,6 @@ import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; -import static testsupport.assertion.MonadErrorAssert.assertLaws; @RunWith(Traits.class) public class TheseTest { @@ -37,4 +36,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + These these = These.pureThese().apply(1); + assertEquals(b(1), these); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index c126b82f8..a3fca2cbf 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -23,6 +23,7 @@ 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.Try.failure; +import static com.jnape.palatable.lambda.adt.Try.pureTry; import static com.jnape.palatable.lambda.adt.Try.success; import static com.jnape.palatable.lambda.adt.Try.trying; import static com.jnape.palatable.lambda.adt.Try.withResources; @@ -258,4 +259,10 @@ public void orThrowCanTransformFirst() { fail("A different exception altogether was thrown."); } } + + @Test + public void staticPure() { + Try try_ = pureTry().apply(1); + assertEquals(success(1), try_); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java index ea4c27160..b163be85d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java @@ -48,4 +48,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Choice2 choice = Choice2.pureChoice().apply((short) 2); + assertEquals(b((short) 2), choice); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java index 2deefbb91..e096f717a 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java @@ -62,4 +62,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Choice3 choice = Choice3.pureChoice().apply(3); + assertEquals(c(3), choice); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java index 1e20850d6..4cc5735bf 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java @@ -70,4 +70,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Choice4 choice = Choice4.pureChoice().apply(4L); + assertEquals(d(4L), choice); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java index bfccafcb9..dc4fef3da 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java @@ -78,4 +78,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Choice5 choice = Choice5.pureChoice().apply(5f); + assertEquals(e(5f), choice); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java index f818d4fd7..c93928ada 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java @@ -90,4 +90,11 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Choice6 choice = + Choice6.pureChoice().apply(6d); + assertEquals(f(6d), choice); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java index 62f2e52d0..5d1eb86a1 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java @@ -98,4 +98,11 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Choice7 choice = + Choice7.pureChoice().apply(true); + assertEquals(g(true), choice); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java index 2b3d4dbe7..6d846d8ec 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java @@ -95,4 +95,11 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Choice8 choice = + Choice8.pureChoice().apply('c'); + assertEquals(h('c'), choice); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java index aae10e80e..fac2a7149 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java @@ -12,6 +12,7 @@ import static com.jnape.palatable.lambda.adt.hlist.HList.nil; import static com.jnape.palatable.lambda.adt.hlist.HList.singletonHList; +import static com.jnape.palatable.lambda.adt.hlist.SingletonHList.pureSingletonHList; import static org.junit.Assert.assertEquals; @RunWith(Traits.class) @@ -48,4 +49,10 @@ public void cons() { public void intoAppliesHeadToFn() { assertEquals("FOO", singletonHList("foo").into(String::toUpperCase)); } + + @Test + public void staticPure() { + SingletonHList singletonHList = pureSingletonHList().apply(1); + assertEquals(singletonHList(1), singletonHList); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index 98ace9007..efc59856d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -19,6 +19,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.adt.hlist.HList.singletonHList; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.adt.hlist.Tuple2.pureTuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -127,4 +128,10 @@ public void fromIterable() { assertEquals(nothing(), Tuple2.fromIterable(singletonList(1))); assertEquals(just(tuple(1, 1)), Tuple2.fromIterable(repeat(1))); } + + @Test + public void staticPure() { + Tuple2 tuple = pureTuple(1).apply("two"); + assertEquals(tuple(1, "two"), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java index 0ae6c5893..d9d3b64ff 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java @@ -15,6 +15,7 @@ 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.hlist.Tuple3.pureTuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -105,4 +106,10 @@ public void fromIterable() { assertEquals(nothing(), Tuple3.fromIterable(singletonList(1))); assertEquals(just(tuple(1, 1, 1)), Tuple3.fromIterable(repeat(1))); } + + @Test + public void staticPure() { + Tuple3 tuple = pureTuple(1, "2").apply('3'); + assertEquals(tuple(1, "2", '3'), tuple); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java index be5168ca2..ffd188a43 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java @@ -15,6 +15,7 @@ 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.hlist.Tuple4.pureTuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -108,4 +109,10 @@ public void fromIterable() { assertEquals(nothing(), Tuple4.fromIterable(singletonList(1))); assertEquals(just(tuple(1, 1, 1, 1)), Tuple4.fromIterable(repeat(1))); } + + @Test + public void staticPure() { + Tuple4 tuple = pureTuple(1, "2", '3').apply(true); + assertEquals(tuple(1, "2", '3', true), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index 7b63b2657..fda932484 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -16,6 +16,7 @@ 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.hlist.Tuple5.pureTuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -114,4 +115,10 @@ public void fromIterable() { assertEquals(nothing(), Tuple5.fromIterable(singletonList(1))); assertEquals(just(tuple(1, 1, 1, 1, 1)), Tuple5.fromIterable(repeat(1))); } + + @Test + public void staticPure() { + Tuple5 tuple = pureTuple(1, "2", '3', true).apply(5f); + assertEquals(tuple(1, "2", '3', true, 5f), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index bad1a776d..6761987a4 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -16,6 +16,7 @@ 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.hlist.Tuple6.pureTuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -118,4 +119,10 @@ public void fromIterable() { assertEquals(nothing(), Tuple6.fromIterable(singletonList(1))); assertEquals(just(tuple(1, 1, 1, 1, 1, 1)), Tuple6.fromIterable(repeat(1))); } + + @Test + public void staticPure() { + Tuple6 tuple = pureTuple(1, "2", '3', true, 5f).apply((byte) 6); + assertEquals(tuple(1, "2", '3', true, 5f, (byte) 6), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index 07fbe09f5..31a5bd68e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -16,6 +16,7 @@ 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.hlist.Tuple7.pureTuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -121,4 +122,11 @@ public void fromIterable() { assertEquals(nothing(), Tuple7.fromIterable(singletonList(1))); assertEquals(just(tuple(1, 1, 1, 1, 1, 1, 1)), Tuple7.fromIterable(repeat(1))); } + + @Test + public void staticPure() { + Tuple7 tuple = + pureTuple((byte) 1, (short) 2, 3, 4L, 5F, 6D).apply(true); + assertEquals(tuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java index c10cecdfd..aebb1b70e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java @@ -16,6 +16,7 @@ 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.hlist.Tuple8.pureTuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -126,4 +127,11 @@ public void fromIterable() { assertEquals(nothing(), Tuple8.fromIterable(singletonList(1))); assertEquals(just(tuple(1, 1, 1, 1, 1, 1, 1, 1)), Tuple8.fromIterable(repeat(1))); } + + @Test + public void staticPure() { + Tuple8 tuple = + pureTuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true).apply('8'); + assertEquals(tuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true, '8'), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index 85db3d418..b603261a0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -90,4 +90,10 @@ public void toFunction() { Function function = add1.toFunction(); assertEquals((Integer) 2, function.apply(1)); } + + @Test + public void staticPure() { + Fn1 fn1 = Fn1.pureFn1().apply(1); + assertEquals((Integer) 1, fn1.apply("anything")); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java b/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java index b46f91f5d..d7d7c9fa4 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java @@ -3,6 +3,7 @@ import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; @@ -12,6 +13,7 @@ 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.traitor.framework.Subjects.subjects; +import static org.junit.Assert.assertEquals; @RunWith(Traits.class) public class RecursiveResultTest { @@ -20,4 +22,10 @@ public class RecursiveResultTest { public Subjects> testSubject() { return subjects(recurse("foo"), terminate(1)); } + + @Test + public void staticPure() { + RecursiveResult recursiveResult = RecursiveResult.pureRecursiveResult().apply(1); + assertEquals(terminate(1), recursiveResult); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java index dc994a3b0..3fea2229f 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java @@ -12,6 +12,9 @@ import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.pureMaybe; +import static com.jnape.palatable.lambda.functor.builtin.Compose.pureCompose; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static org.junit.Assert.assertEquals; @@ -38,4 +41,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + Compose, Maybe, Integer> compose = pureCompose(pureIdentity(), pureMaybe()).apply(1); + assertEquals(new Compose<>(new Identity<>(just(1))), compose); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java index da90a8592..15bc63f74 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java @@ -2,6 +2,7 @@ import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.ApplicativeLaws; import testsupport.traits.BifunctorLaws; @@ -9,6 +10,9 @@ import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; +import static com.jnape.palatable.lambda.functor.builtin.Const.pureConst; +import static org.junit.Assert.assertEquals; + @RunWith(Traits.class) public class ConstTest { @@ -16,4 +20,10 @@ public class ConstTest { public Const testSubject() { return new Const<>(1); } + + @Test + public void staticPure() { + Const constInt = pureConst(1).apply("foo"); + assertEquals(new Const<>(1), constInt); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java index 242a5aaa0..91b57457b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java @@ -2,12 +2,16 @@ import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; import org.junit.runner.RunWith; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; import testsupport.traits.TraversableLaws; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; +import static org.junit.Assert.assertEquals; + @RunWith(Traits.class) public class IdentityTest { @@ -15,4 +19,10 @@ public class IdentityTest { public Identity testSubject() { return new Identity<>(""); } + + @Test + public void staticPure() { + Identity identity = pureIdentity().apply(1); + assertEquals(new Identity<>(1), identity); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java index b169b7870..5f71142f9 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java @@ -14,6 +14,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.pureLazy; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -63,4 +64,10 @@ public Lazy checkedApply(Lazy lazyX) { } }.apply(lazy(0)).value()); } + + @Test + public void staticPure() { + Lazy lazy = pureLazy().apply(1); + assertEquals(lazy(1), lazy); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java index d4009918e..9212246b8 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java @@ -3,18 +3,21 @@ import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; import org.junit.runner.RunWith; import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.trying; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.lang.Integer.parseInt; +import static org.junit.Assert.assertEquals; @RunWith(Traits.class) public class MarketTest { @@ -26,4 +29,11 @@ public class MarketTest { return subjects(new EquatableM<>(market, m -> both(m.bt(), m.sta(), "123")), new EquatableM<>(market, m -> both(m.bt(), m.sta(), "foo"))); } + + @Test + public void staticPure() { + Market market = Market.pureMarket().apply(1); + assertEquals((Integer) 1, market.bt().apply('a')); + assertEquals(left(1), market.sta().apply("foo")); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java index f2071a27e..d1261aa82 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java @@ -80,4 +80,10 @@ public void mapState() { State modified = State.get().mapState(into((a, s) -> product(a + 1, s + 2))); assertEquals(tuple(1, 2), modified.run(0)); } + + @Test + public void staticPure() { + State state = State.pureState().apply(1); + assertEquals(tuple(1, "foo"), state.run("foo")); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/TaggedTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/TaggedTest.java new file mode 100644 index 000000000..085c1fc78 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/TaggedTest.java @@ -0,0 +1,27 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; +import testsupport.traits.TraversableLaws; + +import static org.junit.Assert.assertEquals; + +@RunWith(Traits.class) +public class TaggedTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) + public Tagged testSubject() { + return new Tagged<>(1); + } + + @Test + public void staticPure() { + Tagged tagged = Tagged.pureTagged().apply(1); + assertEquals(new Tagged<>(1), tagged); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index 949a5f091..f35efdd6d 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -39,6 +39,7 @@ import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.io.IO.externallyManaged; import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.io.IO.pureIO; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.lang.Thread.currentThread; import static java.util.Arrays.asList; @@ -441,4 +442,10 @@ public void failuresAreNotMemoized() { assertEquals((Integer) 2, io.unsafePerformIO()); assertEquals((Integer) 2, io.unsafePerformIO()); } + + @Test + public void staticPure() { + IO io = pureIO().apply(1); + assertEquals((Integer) 1, io.unsafePerformIO()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java index 4b7a7a889..c5116c2e3 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java @@ -15,6 +15,7 @@ import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.eitherT; import static com.jnape.palatable.traitor.framework.Subjects.subjects; @@ -37,4 +38,11 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + EitherT, String, Integer> eitherT = EitherT., String>pureEitherT(pureIdentity()) + .apply(1); + assertEquals(eitherT(new Identity<>(right(1))), eitherT); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java index fb9a6629d..44e17b6f0 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java @@ -12,8 +12,10 @@ 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.Maybe.pureMaybe; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT.identityT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT.pureIdentityT; import static org.junit.Assert.assertEquals; @RunWith(Traits.class) @@ -34,4 +36,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + IdentityT, Integer> identityT = pureIdentityT(pureMaybe()).apply(1); + assertEquals(identityT(just(new Identity<>(1))), identityT); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java index 87dffb7e6..85743e4b2 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java @@ -1,6 +1,8 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -11,8 +13,10 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.monad.transformer.builtin.LazyT.lazyT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.LazyT.pureLazyT; import static org.junit.Assert.assertEquals; @RunWith(Traits.class) @@ -33,4 +37,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + LazyT, Integer> lazyT = pureLazyT(pureIdentity()).apply(1); + assertEquals(lazyT(new Identity<>(lazy(1))), lazyT); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java index 9a5368cdc..57273d87c 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -14,8 +15,10 @@ import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.maybeT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.pureMaybeT; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -38,4 +41,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + MaybeT, Integer> maybeT = pureMaybeT(pureIdentity()).apply(1); + assertEquals(maybeT(new Identity<>(just(1))), maybeT); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java index 80af55802..a56aac135 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java @@ -12,6 +12,7 @@ import testsupport.traits.MonadLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.monad.transformer.builtin.ReaderT.readerT; import static org.junit.Assert.assertEquals; @@ -39,4 +40,11 @@ public void mapReaderT() { ., Maybe, Integer>mapReaderT(id -> just(id.runIdentity().length())) .runReaderT("foo")); } + + @Test + public void staticPure() { + ReaderT, Integer> readerT = + ReaderT.>pureReaderT(pureIdentity()).apply(1); + assertEquals(new Identity<>(1), readerT.runReaderT("foo")); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/ComposeTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/ComposeTest.java index d3bf689db..faca56af2 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/ComposeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/ComposeTest.java @@ -15,7 +15,7 @@ public class ComposeTest { @Test public void monoid() throws ExecutionException, InterruptedException { - Monoid addition = Monoid.monoid((x, y) -> x + y, 0); + Monoid addition = Monoid.monoid(Integer::sum, 0); CompletableFuture failedFuture = new CompletableFuture() {{ completeExceptionally(new RuntimeException()); diff --git a/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java index 91c181029..69174c801 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java @@ -54,4 +54,11 @@ public void mapsIndividuallyOverParameters() { assertEquals(just(1), view(mapped, just("1"))); assertEquals(just(asList('1', '.', '2')), view(mapped.mirror(), just(1.2d))); } + + @Test + public void staticPure() { + Iso iso = Iso.pureIso(String::length).apply('1'); + assertEquals((Integer) 3, view(iso, "foo")); + assertEquals((Character) '1', view(iso.mirror(), true)); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java index 1eac70adf..e86080f75 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java @@ -21,6 +21,7 @@ import static com.jnape.palatable.lambda.optics.functions.Matching.matching; import static com.jnape.palatable.lambda.optics.functions.Pre.pre; import static com.jnape.palatable.lambda.optics.functions.Re.re; +import static com.jnape.palatable.lambda.optics.functions.Set.set; import static com.jnape.palatable.lambda.optics.functions.View.view; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -88,4 +89,11 @@ public void composed() { assertPrismLawfulness(composed, singletonList("1.0"), singletonList(1)); assertPrismLawfulness(composed, singletonList("foo"), emptyList()); } + + @Test + public void staticPure() { + Prism prism = Prism.purePrism().apply('1'); + assertEquals(left('1'), matching(prism, "foo")); + assertEquals((Character) '1', set(prism, true, "bar")); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java index 163fa5f20..0abfe0c78 100644 --- a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java @@ -2,6 +2,8 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Functor; +import com.jnape.palatable.lambda.functor.builtin.State; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -14,6 +16,7 @@ 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.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; @@ -21,6 +24,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.traversable.LambdaIterable.empty; +import static com.jnape.palatable.lambda.traversable.LambdaIterable.pureLambdaIterable; import static com.jnape.palatable.lambda.traversable.LambdaIterable.wrap; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.util.Arrays.asList; @@ -67,4 +71,10 @@ public void lazyZip() { throw new AssertionError(); })).value()); } + + @Test + public void staticPure() { + LambdaIterable lambdaIterable = pureLambdaIterable().apply(1); + assertThat(lambdaIterable.unwrap(), iterates(1)); + } } \ No newline at end of file From c0dc47299e055ca8e573da2e2d417d3e506207c5 Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 22 Aug 2019 11:50:54 -0500 Subject: [PATCH 226/348] There is no way Lambda 6 will continue supporting this broken compiler --- .../java/com/jnape/palatable/lambda/adt/Either.java | 3 ++- .../java/com/jnape/palatable/lambda/optics/Iso.java | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) 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 ba75da155..9c63c54a5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -290,8 +290,9 @@ public Either throwError(L l) { * {@inheritDoc} */ @Override + @SuppressWarnings("RedundantTypeArguments") public Either catchError(Fn1>> recoveryFn) { - return match(recoveryFn.fmap(Monad::coerce), Either::right); + return match(recoveryFn.fmap(Monad>::coerce), Either::right); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java index 9aaba84f9..07652a32a 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -15,7 +15,6 @@ import com.jnape.palatable.lambda.optics.functions.View; import static com.jnape.palatable.lambda.functions.Fn1.fn1; -import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.optics.Iso.Simple.adapt; @@ -137,12 +136,13 @@ default Iso discardR(Applicative> appB) { * {@inheritDoc} */ @Override + @SuppressWarnings("RedundantTypeArguments") default Iso flatMap(Fn1>> fn) { - return unIso() - .>fmap(bt -> curried(fn1(bt.fmap(fn.>fmap(Monad::coerce)) - .fmap(Iso::unIso) - .fmap(Tuple2::_2) - .fmap(Fn1::fn1)))) + return unIso().>fmap(bt -> Fn2.curried( + fn1(bt.fmap(fn.>fmap(Monad>::coerce)) + .fmap(Iso::unIso) + .fmap(Tuple2::_2) + .fmap(Fn1::fn1)))) .fmap(Fn2::uncurry) .fmap(bbu -> bbu.diMapL(Tuple2::fill)) .into(Iso::iso); From c78ed71aa93f453dcff43c38bef12aab97696735 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 23 Aug 2019 10:54:10 -0500 Subject: [PATCH 227/348] adding Fn2#curry --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/functions/Fn2.java | 15 +++++++++++++++ .../jnape/palatable/lambda/functions/Fn2Test.java | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0025110c5..a1e77e625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `IO#memoize`, for memoizing an `IO` by caching its first successful result - `MonadError`, monads that can be thrown to and caught from - `Tuple2-8#fromIterable`, for populating a `TupleN` with the first `N` elements of an `Iterable` +- `Fn2#curry`, for converting an `Fn1,C>` to an `Fn2` ## [4.0.0] - 2019-05-20 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java index 0528ff71a..0da885cdf 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn2.java @@ -1,11 +1,13 @@ package com.jnape.palatable.lambda.functions; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.internal.Runtime; import java.util.function.BiFunction; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.Fn3.fn3; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -153,6 +155,19 @@ static Fn2 curried(Fn1> curriedFn1) { return (a, b) -> curriedFn1.apply(a).apply(b); } + /** + * Static factory method for wrapping an uncurried {@link Fn1} in an {@link Fn2}. + * + * @param uncurriedFn1 the uncurried {@link Fn1} to adapt + * @param the first input argument type + * @param the second input argument type + * @param the output type + * @return the {@link Fn2} + */ + static Fn2 curry(Fn1, ? extends C> uncurriedFn1) { + return (a, b) -> uncurriedFn1.apply(tuple(a, b)); + } + /** * Static method to aid inference. * diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java index 71e3a65e3..97a65cd99 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn2Test.java @@ -2,9 +2,11 @@ import org.junit.Test; +import java.util.Map; import java.util.function.BiFunction; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -52,4 +54,10 @@ public void fromBiFunction() { BiFunction biFunction = String::format; assertEquals("foo bar", Fn2.fromBiFunction(biFunction).apply("foo %s", "bar")); } + + @Test + public void curry() { + Fn1, String> uncurried = into((a, b) -> a + b); + assertEquals("foobar", Fn2.curry(uncurried).apply("foo", "bar")); + } } From 803c2c928a2e690883575636c7b25017d011a0f1 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 24 Aug 2019 16:29:45 -0500 Subject: [PATCH 228/348] Default applicative zip evaluation order is now stable left to right - reduction in LiftA2-7 type parameters --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/adt/These.java | 8 +- .../lambda/functions/builtin/fn3/LiftA2.java | 51 ++--- .../lambda/functions/builtin/fn4/LiftA3.java | 73 +++---- .../lambda/functions/builtin/fn5/LiftA4.java | 103 ++++----- .../lambda/functions/builtin/fn6/LiftA5.java | 133 ++++-------- .../lambda/functions/builtin/fn7/LiftA6.java | 181 ++++++---------- .../lambda/functions/builtin/fn8/LiftA7.java | 204 +++++++----------- .../palatable/lambda/functor/Applicative.java | 4 +- .../com/jnape/palatable/lambda/io/IO.java | 5 +- .../jnape/palatable/lambda/monad/Monad.java | 2 +- .../lambda/semigroup/builtin/Absent.java | 2 +- .../jnape/palatable/lambda/adt/TheseTest.java | 4 +- .../lambda/adt/hlist/Tuple2Test.java | 2 +- .../lambda/adt/hlist/Tuple5Test.java | 2 +- .../lambda/adt/hlist/Tuple6Test.java | 2 +- .../lambda/adt/hlist/Tuple7Test.java | 2 +- .../lambda/adt/hlist/Tuple8Test.java | 20 +- .../functions/builtin/fn6/LiftA5Test.java | 3 +- .../functions/builtin/fn7/LiftA6Test.java | 4 +- .../functions/builtin/fn8/LiftA7Test.java | 3 +- .../lambda/functor/builtin/StateTest.java | 10 + .../com/jnape/palatable/lambda/io/IOTest.java | 64 +++++- .../traversable/LambdaIterableTest.java | 7 +- 24 files changed, 378 insertions(+), 512 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1e77e625..87ccc2186 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Changed - ***Breaking Change***: `MonadT` is now witnessed by a parameter for better subtyping +- ***Breaking Change***: `Applicative#zip` and derivatives evaluate from left to right now across the board. - `Alter` now merely requires an `Fn1` instead of an explicit `Effect` - `IO` now internally trampolines all forms of composition, including lazyZip; sequencing very large iterables of IO will work, if you have the heap, and diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index e1aa94c7e..38aba3ff6 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -49,7 +49,13 @@ public final These biMap(Fn1 lFn, */ @Override public final These flatMap(Fn1>> f) { - return match(These::a, b -> f.apply(b).coerce(), into((a, b) -> f.apply(b).>coerce().biMapL(constantly(a)))); + return match(These::a, + b -> f.apply(b).coerce(), + into((a, b) -> f.apply(b) + .>coerce() + .match(constantly(a(a)), + c -> both(a, c), + into((__, c) -> both(a, c))))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java index e83048652..0badec8f5 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LiftA2.java @@ -12,54 +12,43 @@ * @param the function's first argument type * @param the function's second argument type * @param the function's return type - * @param the applicative unification type - * @param the inferred first applicative argument type - * @param the inferred second applicative argument type + * @param the applicative witness * @param the inferred applicative return type * @see Applicative#zip(Applicative) */ -public final class LiftA2, - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative> implements - Fn3, AppA, AppB, AppC> { +public final class LiftA2, AppC extends Applicative> implements + Fn3, Applicative, Applicative, AppC> { - private static final LiftA2 INSTANCE = new LiftA2<>(); + private static final LiftA2 INSTANCE = new LiftA2<>(); private LiftA2() { } @Override - public AppC checkedApply(Fn2 fn, AppA appA, AppB appB) { - return appB.zip(appA.fmap(fn)).coerce(); + public AppC checkedApply(Fn2 fn, + Applicative appA, + Applicative appB) { + return appA.zip(appB.fmap(b -> a -> fn.apply(a, b))).coerce(); } @SuppressWarnings("unchecked") - public static , AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative> LiftA2 liftA2() { - return (LiftA2) INSTANCE; + public static , AppC extends Applicative> + LiftA2 liftA2() { + return (LiftA2) INSTANCE; } - public static , AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative> Fn2 liftA2( - Fn2 fn) { - return LiftA2.liftA2().apply(fn); + public static , AppC extends Applicative> + Fn2, Applicative, AppC> liftA2(Fn2 fn) { + return LiftA2.liftA2().apply(fn); } - public static , AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative> Fn1 liftA2(Fn2 fn, - AppA appA) { - return LiftA2.liftA2(fn).apply(appA); + public static , AppC extends Applicative> + Fn1, AppC> liftA2(Fn2 fn, Applicative appA) { + return LiftA2.liftA2(fn).apply(appA); } - public static , AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative> AppC liftA2(Fn2 fn, - AppA appA, - AppB appB) { - return LiftA2.liftA2(fn, appA).apply(appB); + public static , AppC extends Applicative> + AppC liftA2(Fn2 fn, Applicative appA, Applicative appB) { + return LiftA2.liftA2(fn, appA).apply(appB); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java index b8ccd2527..9000ad81a 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn4/LiftA3.java @@ -14,74 +14,49 @@ * @param the function's second argument type * @param the function's third argument type * @param the function's return type - * @param the applicative unification type - * @param the inferred first applicative argument type - * @param the inferred second applicative argument type - * @param the inferred third applicative argument type + * @param the applicative witness * @param the inferred applicative return type * @see Applicative#zip(Applicative) */ -public final class LiftA3, - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative> implements Fn4, AppA, AppB, AppC, AppD> { +public final class LiftA3, AppD extends Applicative> implements + Fn4, Applicative, Applicative, Applicative, AppD> { - private static final LiftA3 INSTANCE = new LiftA3<>(); + private static final LiftA3 INSTANCE = new LiftA3<>(); private LiftA3() { } @Override - public AppD checkedApply(Fn3 fn, AppA appA, AppB appB, AppC appC) { - return appC.zip(appB.zip(appA.fmap(fn))).coerce(); + public AppD checkedApply(Fn3 fn, + Applicative appA, + Applicative appB, + Applicative appC) { + return appA.zip(appB.zip(appC.fmap(c -> b -> a -> fn.apply(a, b, c)))).coerce(); } @SuppressWarnings("unchecked") - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative> LiftA3 liftA3() { - return (LiftA3) INSTANCE; + public static , AppD extends Applicative> + LiftA3 liftA3() { + return (LiftA3) INSTANCE; } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative> Fn3 liftA3(Fn3 fn) { - return LiftA3.liftA3().apply(fn); + public static , AppD extends Applicative> + Fn3, Applicative, Applicative, AppD> liftA3(Fn3 fn) { + return LiftA3.liftA3().apply(fn); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative> Fn2 liftA3(Fn3 fn, AppA appA) { - return LiftA3.liftA3(fn).apply(appA); + public static , AppD extends Applicative> + Fn2, Applicative, AppD> liftA3(Fn3 fn, Applicative appA) { + return LiftA3.liftA3(fn).apply(appA); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative> Fn1 liftA3(Fn3 fn, AppA appA, AppB appB) { - return LiftA3.liftA3(fn, appA).apply(appB); + public static , AppD extends Applicative> + Fn1, AppD> liftA3(Fn3 fn, Applicative appA, Applicative appB) { + return LiftA3.liftA3(fn, appA).apply(appB); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative> AppD liftA3(Fn3 fn, AppA appA, AppB appB, - AppC appC) { - return LiftA3.liftA3(fn, appA, appB).apply(appC); + public static , AppD extends Applicative> + AppD liftA3(Fn3 fn, Applicative appA, Applicative appB, Applicative appC) { + return LiftA3.liftA3(fn, appA, appB).apply(appC); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java index 408f94652..9132376dc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn5/LiftA4.java @@ -16,93 +16,64 @@ * @param the function's third argument type * @param the function's fourth argument type * @param the function's return type - * @param the applicative unification type - * @param the inferred first applicative argument type - * @param the inferred second applicative argument type - * @param the inferred third applicative argument type - * @param the inferred fourth applicative argument type + * @param the applicative witness * @param the inferred applicative return type * @see Applicative#zip(Applicative) */ -public final class LiftA4, - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative> implements Fn5, AppA, AppB, AppC, AppD, AppE> { +public final class LiftA4, AppE extends Applicative> implements + Fn5, Applicative, Applicative, Applicative, Applicative, + AppE> { - private static final LiftA4 INSTANCE = new LiftA4<>(); + private static final LiftA4 INSTANCE = new LiftA4<>(); private LiftA4() { } @Override - public AppE checkedApply(Fn4 fn, AppA appA, AppB appB, AppC appC, AppD appD) { - return appD.zip(appC.zip(appB.zip(appA.fmap(fn)))).coerce(); + public AppE checkedApply(Fn4 fn, Applicative appA, Applicative appB, + Applicative appC, Applicative appD) { + return appA.zip(appB.zip(appC.zip(appD.fmap(d -> c -> b -> a -> fn.apply(a, b, c, d))))).coerce(); } @SuppressWarnings("unchecked") - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative> LiftA4 liftA4() { - return (LiftA4) INSTANCE; + public static , AppE extends Applicative> + LiftA4 liftA4() { + return (LiftA4) INSTANCE; } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative> Fn4 liftA4(Fn4 fn) { - return LiftA4.liftA4().apply(fn); + public static , AppE extends Applicative> + Fn4, Applicative, Applicative, Applicative, AppE> liftA4( + Fn4 fn) { + return LiftA4.liftA4().apply(fn); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative> Fn3 liftA4(Fn4 fn, AppA appA) { - return LiftA4.liftA4(fn).apply(appA); + public static , AppE extends Applicative> + Fn3, Applicative, Applicative, AppE> liftA4(Fn4 fn, + Applicative appA) { + return LiftA4.liftA4(fn).apply(appA); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative> Fn2 liftA4(Fn4 fn, AppA appA, - AppB appB) { - return LiftA4.liftA4(fn, appA).apply(appB); + public static , AppE extends Applicative> + Fn2, Applicative, AppE> liftA4(Fn4 fn, + Applicative appA, + Applicative appB) { + return LiftA4.liftA4(fn, appA).apply(appB); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative> Fn1 liftA4(Fn4 fn, AppA appA, AppB appB, - AppC appC) { - return LiftA4.liftA4(fn, appA, appB).apply(appC); + public static , AppE extends Applicative> + Fn1, AppE> liftA4(Fn4 fn, + Applicative appA, + Applicative appB, + Applicative appC) { + return LiftA4.liftA4(fn, appA, appB).apply(appC); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative> AppE liftA4(Fn4 fn, AppA appA, AppB appB, - AppC appC, AppD appD) { - return LiftA4.liftA4(fn, appA, appB, appC).apply(appD); + public static , AppE extends Applicative> + AppE liftA4(Fn4 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD) { + return LiftA4.liftA4(fn, appA, appB, appC).apply(appD); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java index 4711de30a..7fd7c8f4f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5.java @@ -18,115 +18,76 @@ * @param the function's fourth argument type * @param the function's fifth argument type * @param the function's return type - * @param the applicative unification type - * @param the inferred first applicative argument type - * @param the inferred second applicative argument type - * @param the inferred third applicative argument type - * @param the inferred fourth applicative argument type - * @param the inferred fifth applicative argument type + * @param the applicative witness * @param the inferred applicative return type * @see Applicative#zip(Applicative) */ -public final class LiftA5, - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative> implements Fn6, AppA, AppB, AppC, AppD, AppE, AppF> { +public final class LiftA5, AppF extends Applicative> + implements Fn6, Applicative, Applicative, Applicative, + Applicative, Applicative, AppF> { - private static final LiftA5 INSTANCE = new LiftA5<>(); + private static final LiftA5 INSTANCE = new LiftA5<>(); private LiftA5() { } @Override - public AppF checkedApply(Fn5 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE) { - return appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn))))).coerce(); + public AppF checkedApply(Fn5 fn, Applicative appA, Applicative appB, + Applicative appC, Applicative appD, Applicative appE) { + return appA.zip(appB.zip(appC.zip(appD.zip(appE.fmap(e -> d -> c -> b -> a -> fn.apply(a, b, c, d, e)))))) + .coerce(); } @SuppressWarnings("unchecked") - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative> LiftA5 liftA5() { - return (LiftA5) INSTANCE; + public static , AppF extends Applicative> + LiftA5 liftA5() { + return (LiftA5) INSTANCE; } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative> Fn5 liftA5(Fn5 fn) { - return LiftA5.liftA5().apply(fn); + public static , AppF extends Applicative> + Fn5, Applicative, Applicative, Applicative, Applicative, AppF> + liftA5(Fn5 fn) { + return LiftA5.liftA5().apply(fn); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative> Fn4 liftA5(Fn5 fn, - AppA appA) { - return LiftA5.liftA5(fn).apply(appA); + public static , AppF extends Applicative> + Fn4, Applicative, Applicative, Applicative, AppF> + liftA5(Fn5 fn, + Applicative appA) { + return LiftA5.liftA5(fn).apply(appA); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative> Fn3 liftA5(Fn5 fn, AppA appA, - AppB appB) { - return LiftA5.liftA5(fn, appA).apply(appB); + public static , AppF extends Applicative> + Fn3, Applicative, Applicative, AppF> liftA5(Fn5 fn, + Applicative appA, + Applicative appB) { + return LiftA5.liftA5(fn, appA).apply(appB); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative> Fn2 liftA5(Fn5 fn, AppA appA, - AppB appB, - AppC appC) { - return LiftA5.liftA5(fn, appA, appB).apply(appC); + public static , AppF extends Applicative> + Fn2, Applicative, AppF> liftA5(Fn5 fn, + Applicative appA, + Applicative appB, + Applicative appC) { + return LiftA5.liftA5(fn, appA, appB).apply(appC); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative> Fn1 liftA5(Fn5 fn, AppA appA, AppB appB, - AppC appC, AppD appD) { - return LiftA5.liftA5(fn, appA, appB, appC).apply(appD); + public static , AppF extends Applicative> + Fn1, AppF> liftA5(Fn5 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD) { + return LiftA5.liftA5(fn, appA, appB, appC).apply(appD); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative> AppF liftA5(Fn5 fn, AppA appA, AppB appB, - AppC appC, AppD appD, AppE appE) { - return LiftA5.liftA5(fn, appA, appB, appC, appD).apply(appE); + public static , AppF extends Applicative> + AppF liftA5(Fn5 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD, + Applicative appE) { + return LiftA5.liftA5(fn, appA, appB, appC, appD).apply(appE); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java index 90234684d..fcc7934c9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6.java @@ -20,145 +20,98 @@ * @param the function's fifth argument type * @param the function's sixth argument type * @param the function's return type - * @param the applicative unification type - * @param the inferred first applicative argument type - * @param the inferred second applicative argument type - * @param the inferred third applicative argument type - * @param the inferred fourth applicative argument type - * @param the inferred fifth applicative argument type - * @param the inferred sixth applicative argument type + * @param the applicative witness * @param the inferred applicative return type * @see Applicative#zip(Applicative) */ -public final class LiftA6, - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative> implements - Fn7, AppA, AppB, AppC, AppD, AppE, AppF, AppG> { +public final class LiftA6, AppG extends Applicative> + implements Fn7, + Applicative, + Applicative, + Applicative, + Applicative, + Applicative, + Applicative, + AppG> { - private static final LiftA6 INSTANCE = new LiftA6<>(); + private static final LiftA6 INSTANCE = new LiftA6<>(); private LiftA6() { } @Override - public AppG checkedApply(Fn6 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, - AppF appF) { - return appF.zip(appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn)))))).coerce(); + public AppG checkedApply(Fn6 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD, + Applicative appE, + Applicative appF) { + return appA.zip(appB.zip(appC.zip(appD.zip(appE.zip(appF.fmap( + f -> e -> d -> c -> b -> a -> fn.apply(a, b, c, d, e, f))))))).coerce(); } - @SuppressWarnings("unchecked") - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative> - LiftA6 liftA6() { - return (LiftA6) INSTANCE; + public static , AppG extends Applicative> + LiftA6 liftA6() { + return (LiftA6) INSTANCE; } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative> Fn6 liftA6( - Fn6 fn) { - return LiftA6.liftA6().apply(fn); + public static , AppG extends Applicative> + Fn6, Applicative, Applicative, Applicative, Applicative, + Applicative, AppG> liftA6(Fn6 fn) { + return LiftA6.liftA6().apply(fn); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative> Fn5 liftA6( - Fn6 fn, - AppA appA) { - return LiftA6.liftA6(fn).apply(appA); + public static , AppG extends Applicative> + Fn5, Applicative, Applicative, Applicative, Applicative, AppG> + liftA6(Fn6 fn, Applicative appA) { + return LiftA6.liftA6(fn).apply(appA); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative> Fn4 liftA6(Fn6 fn, - AppA appA, - AppB appB) { - return LiftA6.liftA6(fn, appA).apply(appB); + public static , AppG extends Applicative> + Fn4, Applicative, Applicative, Applicative, AppG> + liftA6(Fn6 fn, + Applicative appA, + Applicative appB) { + return LiftA6.liftA6(fn, appA).apply(appB); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative> Fn3 liftA6(Fn6 fn, AppA appA, - AppB appB, - AppC appC) { - return LiftA6.liftA6(fn, appA, appB).apply(appC); + public static , AppG extends Applicative> + Fn3, Applicative, Applicative, AppG> liftA6(Fn6 fn, + Applicative appA, + Applicative appB, + Applicative appC) { + return LiftA6.liftA6(fn, appA, appB).apply(appC); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative> Fn2 liftA6(Fn6 fn, AppA appA, - AppB appB, - AppC appC, AppD appD) { - return LiftA6.liftA6(fn, appA, appB, appC).apply(appD); + public static , AppG extends Applicative> + Fn2, Applicative, AppG> liftA6(Fn6 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD) { + return LiftA6.liftA6(fn, appA, appB, appC).apply(appD); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative> Fn1 liftA6(Fn6 fn, AppA appA, AppB appB, - AppC appC, AppD appD, AppE appE) { - return LiftA6.liftA6(fn, appA, appB, appC, appD).apply(appE); + public static , AppG extends Applicative> + Fn1, AppG> liftA6(Fn6 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD, + Applicative appE) { + return LiftA6.liftA6(fn, appA, appB, appC, appD).apply(appE); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative> AppG liftA6(Fn6 fn, AppA appA, AppB appB, - AppC appC, AppD appD, AppE appE, AppF appF) { - return LiftA6.liftA6(fn, appA, appB, appC, appD, appE).apply(appF); + public static , AppG extends Applicative> + AppG liftA6(Fn6 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD, + Applicative appE, + Applicative appF) { + return LiftA6.liftA6(fn, appA, appB, appC, appD, appE).apply(appF); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java index 90eab07a5..6f80b7d37 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7.java @@ -23,164 +23,106 @@ * @param the function's seventh argument type * @param the function's return type * @param the applicative unification type - * @param the inferred first applicative argument type - * @param the inferred second applicative argument type - * @param the inferred third applicative argument type - * @param the inferred fourth applicative argument type - * @param the inferred fifth applicative argument type - * @param the inferred sixth applicative argument type - * @param the inferred seventh applicative argument type * @param the inferred applicative return type * @see Applicative#zip(Applicative) */ -public final class LiftA7, - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> implements Fn8, AppA, AppB, AppC, AppD, AppE, AppF, AppG, AppH> { +public final class LiftA7, AppH extends Applicative> + implements Fn8, Applicative, Applicative, Applicative, + Applicative, Applicative, Applicative, Applicative, AppH> { - private static final LiftA7 INSTANCE = new LiftA7<>(); + private static final LiftA7 INSTANCE = new LiftA7<>(); private LiftA7() { } @Override - public AppH checkedApply(Fn7 fn, AppA appA, AppB appB, AppC appC, AppD appD, AppE appE, - AppF appF, AppG appG) { - return appG.zip(appF.zip(appE.zip(appD.zip(appC.zip(appB.zip(appA.fmap(fn))))))).coerce(); + public AppH checkedApply(Fn7 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD, + Applicative appE, + Applicative appF, + Applicative appG) { + return appA.zip(appB.zip(appC.zip(appD.zip(appE.zip(appF.zip(appG.fmap( + g -> f -> e -> d -> c -> b -> a -> fn.apply(a, b, c, d, e, f, g)))))))).coerce(); } @SuppressWarnings("unchecked") - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> LiftA7 liftA7() { - return (LiftA7) INSTANCE; + public static , AppH extends Applicative> + LiftA7 liftA7() { + return (LiftA7) INSTANCE; } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> Fn7 liftA7( - Fn7 fn) { - return LiftA7.liftA7().apply(fn); + public static , AppH extends Applicative> + Fn7, Applicative, Applicative, Applicative, Applicative, + Applicative, Applicative, AppH> liftA7(Fn7 fn) { + return LiftA7.liftA7().apply(fn); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> Fn6 liftA7( - Fn7 fn, AppA appA) { - return LiftA7.liftA7(fn).apply(appA); + public static , AppH extends Applicative> + Fn6, Applicative, Applicative, Applicative, Applicative, + Applicative, AppH> liftA7(Fn7 fn, + Applicative appA) { + return LiftA7.liftA7(fn).apply(appA); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> Fn5 liftA7( - Fn7 fn, AppA appA, AppB appB) { - return LiftA7.liftA7(fn, appA).apply(appB); + public static , AppH extends Applicative> + Fn5, Applicative, Applicative, Applicative, Applicative, AppH> + liftA7(Fn7 fn, + Applicative appA, + Applicative appB) { + return LiftA7.liftA7(fn, appA).apply(appB); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> Fn4 liftA7(Fn7 fn, - AppA appA, AppB appB, - AppC appC) { - return LiftA7.liftA7(fn, appA, appB).apply(appC); + public static , AppH extends Applicative> + Fn4, Applicative, Applicative, Applicative, AppH> liftA7( + Fn7 fn, + Applicative appA, + Applicative appB, + Applicative appC) { + return LiftA7.liftA7(fn, appA, appB).apply(appC); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> Fn3 liftA7(Fn7 fn, - AppA appA, AppB appB, AppC appC, - AppD appD) { - return LiftA7.liftA7(fn, appA, appB, appC).apply(appD); + public static , AppH extends Applicative> + Fn3, Applicative, Applicative, AppH> liftA7(Fn7 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD) { + return LiftA7.liftA7(fn, appA, appB, appC).apply(appD); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> Fn2 liftA7(Fn7 fn, AppA appA, - AppB appB, AppC appC, AppD appD, AppE appE) { - return LiftA7.liftA7(fn, appA, appB, appC, appD).apply(appE); + public static , AppH extends Applicative> + Fn2, Applicative, AppH> liftA7(Fn7 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD, + Applicative appE) { + return LiftA7.liftA7(fn, appA, appB, appC, appD).apply(appE); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> Fn1 liftA7(Fn7 fn, AppA appA, - AppB appB, AppC appC, AppD appD, AppE appE, - AppF appF) { - return LiftA7.liftA7(fn, appA, appB, appC, appD, appE).apply(appF); + public static , AppH extends Applicative> + Fn1, AppH> liftA7(Fn7 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD, + Applicative appE, + Applicative appF) { + return LiftA7.liftA7(fn, appA, appB, appC, appD, appE).apply(appF); } - public static , - AppA extends Applicative, - AppB extends Applicative, - AppC extends Applicative, - AppD extends Applicative, - AppE extends Applicative, - AppF extends Applicative, - AppG extends Applicative, - AppH extends Applicative> AppH liftA7(Fn7 fn, AppA appA, AppB appB, - AppC appC, AppD appD, AppE appE, AppF appF, AppG appG) { - return LiftA7.liftA7(fn, appA, appB, appC, appD, appE, appF).apply(appG); + public static , AppH extends Applicative> + AppH liftA7(Fn7 fn, + Applicative appA, + Applicative appB, + Applicative appC, + Applicative appD, + Applicative appE, + Applicative appF, + Applicative appG) { + return LiftA7.liftA7(fn, appA, appB, appC, appD, appE, appF).apply(appG); } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java index 4dd634e13..78a485bf2 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java @@ -78,7 +78,7 @@ default Applicative fmap(Fn1 fn) { * @return appB */ default Applicative discardL(Applicative appB) { - return appB.zip(fmap(constantly(id()))); + return zip(appB.fmap(constantly())); } /** @@ -90,6 +90,6 @@ default Applicative discardL(Applicative appB) { * @return this Applicative */ default Applicative discardR(Applicative appB) { - return appB.zip(fmap(constantly())); + return zip(appB.fmap(constantly(id()))); } } diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index fe5eeb7b4..cd3cc3fd0 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -10,9 +10,7 @@ import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; -import com.jnape.palatable.lambda.functor.builtin.State; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadError; @@ -23,7 +21,6 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; -import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; @@ -403,7 +400,7 @@ public CompletableFuture unsafePerformAsyncIO(Executor executor) { * * @return the {@link Pure} instance */ - public static Pure> pureIO() { + public static Pure> pureIO() { return IO::io; } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java index 769218304..1c5645905 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java @@ -56,7 +56,7 @@ default Monad fmap(Fn1 fn) { */ @Override default Monad zip(Applicative, M> appFn) { - return appFn., M>>coerce().flatMap(this::fmap); + return flatMap(a -> appFn., M>>coerce().fmap(f -> f.apply(a))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java index f39fd05cd..a692eac77 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java @@ -32,7 +32,7 @@ private Absent() { @Override public Semigroup> checkedApply(Semigroup aSemigroup) { - return LiftA2., Maybe, Maybe, Maybe>liftA2(aSemigroup)::apply; + return LiftA2., Maybe>liftA2(aSemigroup)::apply; } @SuppressWarnings("unchecked") diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java index be958203e..648b82ee6 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java @@ -29,8 +29,8 @@ public Subjects> testSubject() { @Test public void lazyZip() { assertEquals(b(2), b(1).lazyZip(lazy(b(x -> x + 1))).value()); - assertEquals(b(2), b(1).lazyZip(lazy(both("foo", x -> x + 1))).value()); - assertEquals(both("bar", 2), both("foo", 1).lazyZip(lazy(both("bar", x -> x + 1))).value()); + assertEquals(both("foo", 2), b(1).lazyZip(lazy(both("foo", x -> x + 1))).value()); + assertEquals(both("foo", 2), both("foo", 1).lazyZip(lazy(both("bar", x -> x + 1))).value()); assertEquals(both("foo", 2), both("foo", 1).lazyZip(lazy(b(x -> x + 1))).value()); assertEquals(a(1), a(1).lazyZip(lazy(() -> { throw new AssertionError(); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index efc59856d..c66438442 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -112,7 +112,7 @@ public void staticFactoryMethodFromMapEntry() { public void zipPrecedence() { Tuple2 a = tuple("foo", 1); Tuple2> b = tuple("bar", x -> x + 1); - assertEquals(tuple("bar", 2), a.zip(b)); + assertEquals(tuple("foo", 2), a.zip(b)); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index fda932484..45236d2f1 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -99,7 +99,7 @@ public void zipPrecedence() { tuple("foo", 1, 2, 3, 4); Tuple5> b = tuple("bar", 2, 3, 4, x -> x + 1); - assertEquals(tuple("bar", 2, 3, 4, 5), a.zip(b)); + assertEquals(tuple("foo", 1, 2, 3, 5), a.zip(b)); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index 6761987a4..604dee77f 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -103,7 +103,7 @@ public void zipPrecedence() { tuple("foo", 1, 2, 3, 4, 5); Tuple6> b = tuple("bar", 2, 3, 4, 5, x -> x + 1); - assertEquals(tuple("bar", 2, 3, 4, 5, 6), a.zip(b)); + assertEquals(tuple("foo", 1, 2, 3, 4, 6), a.zip(b)); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index 31a5bd68e..22d8bcc84 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -106,7 +106,7 @@ public void zipPrecedence() { tuple("foo", 1, 2, 3, 4, 5, 6); Tuple7> b = tuple("bar", 2, 3, 4, 5, 6, x -> x + 1); - assertEquals(tuple("bar", 2, 3, 4, 5, 6, 7), a.zip(b)); + assertEquals(tuple("foo", 1, 2, 3, 4, 5, 7), a.zip(b)); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java index aebb1b70e..6f67a6cb6 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java @@ -33,7 +33,9 @@ public class Tuple8Test { @Before public void setUp() { - tuple8 = new Tuple8<>((short) 65535, new Tuple7<>((byte) 127, new Tuple6<>(2.0f, new Tuple5<>(1, new Tuple4<>("2", new Tuple3<>('3', new Tuple2<>(false, new SingletonHList<>(5L)))))))); + Tuple2 tuple2 = new Tuple2<>(false, new SingletonHList<>(5L)); + Tuple4 tuple4 = new Tuple4<>("2", new Tuple3<>('3', tuple2)); + tuple8 = new Tuple8<>((short) 65535, new Tuple7<>((byte) 127, new Tuple6<>(2.0f, new Tuple5<>(1, tuple4)))); } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) @@ -48,8 +50,9 @@ public void head() { @Test public void tail() { - assertEquals(new Tuple7<>((byte) 127, new Tuple6<>(2.0f, new Tuple5<>(1, new Tuple4<>("2", new Tuple3<>('3', new Tuple2<>(false, new SingletonHList<>(5L))))))), - tuple8.tail()); + Tuple2 tuple2 = new Tuple2<>(false, new SingletonHList<>(5L)); + Tuple4 tuple4 = new Tuple4<>("2", new Tuple3<>('3', tuple2)); + assertEquals(new Tuple7<>((byte) 127, new Tuple6<>(2.0f, new Tuple5<>(1, tuple4))), tuple8.tail()); } @Test @@ -71,8 +74,10 @@ public void accessors() { @Test public void randomAccess() { - Tuple7 spiedTail = spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh", "eighth")); - Tuple8 tuple8 = new Tuple8<>("first", spiedTail); + Tuple7 spiedTail = + spy(tuple("second", "third", "fourth", "fifth", "sixth", "seventh", "eighth")); + Tuple8 tuple8 = + new Tuple8<>("first", spiedTail); verify(spiedTail, times(1))._1(); verify(spiedTail, times(1))._2(); @@ -99,7 +104,8 @@ public void fill() { @Test public void into() { - Tuple8 tuple = tuple("foo", 1, 2.0d, false, 3f, (short) 4, (byte) 5, 6L); + Tuple8 tuple = + tuple("foo", 1, 2.0d, false, 3f, (short) 4, (byte) 5, 6L); assertEquals("foo12.0false3.0456", tuple.into((s, i, d, b, f, sh, by, l) -> s + i + d + b + f + sh + by + l)); } @@ -109,7 +115,7 @@ public void zipPrecedence() { = tuple("foo", 1, 2, 3, 4, 5, 6, 7); Tuple8> b = tuple("bar", 2, 3, 4, 5, 6, 7, x -> x + 1); - assertEquals(tuple("bar", 2, 3, 4, 5, 6, 7, 8), a.zip(b)); + assertEquals(tuple("foo", 1, 2, 3, 4, 5, 6, 8), a.zip(b)); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5Test.java index 0d1851d34..bd131e897 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn6/LiftA5Test.java @@ -10,6 +10,7 @@ public class LiftA5Test { @Test public void lifting() { - assertEquals(just(15), liftA5((a, b, c, d, e) -> a + b + c + d + e, just(1), just(2), just(3), just(4), just(5))); + assertEquals(just(15), + liftA5((a, b, c, d, e) -> a + b + c + d + e, just(1), just(2), just(3), just(4), just(5))); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6Test.java index a247e5620..76ed29162 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn7/LiftA6Test.java @@ -10,6 +10,8 @@ public class LiftA6Test { @Test public void lifting() { - assertEquals(just(21), liftA6((a, b, c, d, e, f) -> a + b + c + d + e + f, just(1), just(2), just(3), just(4), just(5), just(6))); + assertEquals(just(21), + liftA6((a, b, c, d, e, f) -> a + b + c + d + e + f, + just(1), just(2), just(3), just(4), just(5), just(6))); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7Test.java index 73297afde..f81bd6ef0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn8/LiftA7Test.java @@ -10,6 +10,7 @@ public class LiftA7Test { @Test public void lifting() { - assertEquals(just(28), liftA7((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g, just(1), just(2), just(3), just(4), just(5), just(6), just(7))); + assertEquals(just(28), liftA7((a, b, c, d, e, f, g) -> a + b + c + d + e + f + g, + just(1), just(2), just(3), just(4), just(5), just(6), just(7))); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java index d1261aa82..0dded6598 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java @@ -2,6 +2,8 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.hlist.HList; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -69,6 +71,14 @@ public void stateAccumulation() { assertEquals(tuple(0, 1), counter.run(0)); } + @Test + public void zipOrdering() { + Tuple2 result = State.state(s -> tuple(0, s + "1")) + .zip(State.>state(s -> tuple(x -> x + 1, s + "2"))) + .run("_"); + assertEquals(tuple(1, "_12"), result); + } + @Test public void withState() { State modified = State.get().withState(x -> x + 1); diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index f35efdd6d..b3bda711d 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -4,7 +4,6 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.builtin.fn2.Sequence; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Rule; @@ -33,6 +32,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Sequence.sequence; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; import static com.jnape.palatable.lambda.functions.builtin.fn3.LiftA2.liftA2; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; @@ -45,6 +45,7 @@ import static java.util.Arrays.asList; import static java.util.concurrent.CompletableFuture.completedFuture; import static java.util.concurrent.Executors.newFixedThreadPool; +import static java.util.concurrent.Executors.newSingleThreadExecutor; import static java.util.concurrent.ForkJoinPool.commonPool; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; @@ -300,13 +301,13 @@ public void staggeredZipAndFlatMapStackSafety() { @Test public void sequenceStackSafety() { assertEquals(STACK_EXPLODING_NUMBER, - Sequence.sequence(replicate(STACK_EXPLODING_NUMBER, io(UNIT)), IO::io) + sequence(replicate(STACK_EXPLODING_NUMBER, io(UNIT)), IO::io) .fmap(size()) .fmap(Long::intValue) .unsafePerformIO()); assertEquals(STACK_EXPLODING_NUMBER, - Sequence.sequence(replicate(STACK_EXPLODING_NUMBER, io(UNIT)), IO::io) + sequence(replicate(STACK_EXPLODING_NUMBER, io(UNIT)), IO::io) .fmap(size()) .fmap(Long::intValue) .unsafePerformAsyncIO().join()); @@ -316,7 +317,7 @@ public void sequenceStackSafety() { public void sequenceIOExecutesInParallel() { int n = 2; CountDownLatch latch = new CountDownLatch(n); - Sequence.sequence(replicate(n, io(() -> { + sequence(replicate(n, io(() -> { latch.countDown(); if (!latch.await(100, MILLISECONDS)) { throw new AssertionError("Expected latch to countDown in time, but didn't."); @@ -328,7 +329,7 @@ public void sequenceIOExecutesInParallel() { @Test public void sequenceIsRepeatable() { - IO> io = Sequence.sequence(replicate(3, io(UNIT)), IO::io); + IO> io = sequence(replicate(3, io(UNIT)), IO::io); assertEquals((Long) 3L, size(io.unsafePerformIO())); assertEquals((Long) 3L, size(io.unsafePerformIO())); @@ -448,4 +449,57 @@ public void staticPure() { IO io = pureIO().apply(1); assertEquals((Integer) 1, io.unsafePerformIO()); } + + @Test + public void zipExecutionOrdering() { + List invocationsSync = new ArrayList<>(); + io(() -> invocationsSync.add("one")) + .zip(io(() -> invocationsSync.add("two")) + .zip(io(() -> invocationsSync.add("three")).fmap(x -> y -> z -> z))) + .unsafePerformIO(); + assertEquals(asList("one", "two", "three"), invocationsSync); + + List invocationsAsync = new ArrayList<>(); + io(() -> invocationsAsync.add("one")) + .zip(io(() -> invocationsAsync.add("two")) + .zip(io(() -> invocationsAsync.add("three")).fmap(x -> y -> z -> z))) + .unsafePerformAsyncIO(newSingleThreadExecutor()).join(); + assertEquals(asList("one", "two", "three"), invocationsSync); + } + + @Test + public void discardLExecutionOrdering() { + List invocationsSync = new ArrayList<>(); + io(() -> invocationsSync.add("one")) + .discardL(io(() -> invocationsSync.add("two"))) + .discardL(io(() -> invocationsSync.add("three"))) + .unsafePerformIO(); + assertEquals(asList("one", "two", "three"), invocationsSync); + + List invocationsAsync = new ArrayList<>(); + io(() -> invocationsAsync.add("one")) + .discardL(io(() -> invocationsAsync.add("two"))) + .discardL(io(() -> invocationsAsync.add("three"))) + .unsafePerformAsyncIO(newSingleThreadExecutor()) + .join(); + assertEquals(asList("one", "two", "three"), invocationsSync); + } + + @Test + public void discardRExecutionOrdering() { + List invocationsSync = new ArrayList<>(); + io(() -> invocationsSync.add("one")) + .discardR(io(() -> invocationsSync.add("two"))) + .discardR(io(() -> invocationsSync.add("three"))) + .unsafePerformIO(); + assertEquals(asList("one", "two", "three"), invocationsSync); + + List invocationsAsync = new ArrayList<>(); + io(() -> invocationsAsync.add("one")) + .discardR(io(() -> invocationsAsync.add("two"))) + .discardR(io(() -> invocationsAsync.add("three"))) + .unsafePerformAsyncIO(newSingleThreadExecutor()) + .join(); + assertEquals(asList("one", "two", "three"), invocationsSync); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java index 0abfe0c78..ead979b2c 100644 --- a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java @@ -2,8 +2,6 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functor.Functor; -import com.jnape.palatable.lambda.functor.builtin.State; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -16,7 +14,6 @@ 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.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; @@ -44,9 +41,9 @@ public Subjects> testSubject() { @Test public void zipAppliesCartesianProductOfFunctionsAndValues() { - LambdaIterable> fns = wrap(asList(x -> x + 1, x -> x - 1)); LambdaIterable xs = wrap(asList(1, 2, 3)); - assertThat(xs.zip(fns).unwrap(), iterates(2, 3, 4, 0, 1, 2)); + LambdaIterable> fns = wrap(asList(x -> x + 1, x -> x - 1)); + assertThat(xs.zip(fns).unwrap(), iterates(2, 0, 3, 1, 4, 2)); } @Test From 067056fbd992dd50d3959010fce1df7d3523d55e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 18 Aug 2019 12:56:41 -0500 Subject: [PATCH 229/348] MonadT changes - MonadBase lifting infrastructure separate from MonadT - MonadT no longer demands run method but merely conjoins MonadBase to Monad - added StateT and WriterT - added MonadReader and MonadWriter - added Lift type - EqualityM replaced with Equivalence --- CHANGELOG.md | 48 ++- pom.xml | 2 +- .../palatable/lambda/adt/hlist/Tuple2.java | 31 +- .../jnape/palatable/lambda/adt/hmap/HMap.java | 3 +- .../lambda/adt/hmap/TypeSafeKey.java | 2 +- .../jnape/palatable/lambda/functions/Fn1.java | 37 ++- .../lambda/functions/specialized/Lift.java | 37 +++ .../palatable/lambda/functor/Applicative.java | 13 +- .../palatable/lambda/functor/Cartesian.java | 12 + .../lambda/functor/builtin/State.java | 84 +++-- .../internal/iteration/GroupingIterator.java | 2 +- .../com/jnape/palatable/lambda/io/IO.java | 2 +- .../palatable/lambda/monad/MonadBase.java | 22 ++ .../palatable/lambda/monad/MonadError.java | 2 +- .../palatable/lambda/monad/MonadReader.java | 83 +++++ .../palatable/lambda/monad/MonadWriter.java | 87 +++++ .../lambda/monad/transformer/MonadT.java | 47 +-- .../monad/transformer/builtin/EitherT.java | 38 ++- .../monad/transformer/builtin/IdentityT.java | 36 ++- .../monad/transformer/builtin/LazyT.java | 38 ++- .../monad/transformer/builtin/MaybeT.java | 36 ++- .../monad/transformer/builtin/ReaderT.java | 52 ++- .../monad/transformer/builtin/StateT.java | 298 ++++++++++++++++++ .../monad/transformer/builtin/WriterT.java | 202 ++++++++++++ .../palatable/lambda/functions/Fn1Test.java | 15 +- .../lambda/functor/builtin/LazyTest.java | 7 +- .../lambda/functor/builtin/MarketTest.java | 9 +- .../lambda/functor/builtin/StateTest.java | 21 +- .../com/jnape/palatable/lambda/io/IOTest.java | 11 +- .../transformer/builtin/ReaderTTest.java | 19 +- .../monad/transformer/builtin/StateTTest.java | 119 +++++++ .../transformer/builtin/WriterTTest.java | 66 ++++ .../palatable/lambda/optics/IsoTest.java | 7 +- .../palatable/lambda/optics/LensTest.java | 16 +- .../palatable/lambda/optics/PrismTest.java | 9 +- src/test/java/testsupport/EquatableM.java | 79 ----- .../assertion/MonadErrorAssert.java | 39 +-- .../testsupport/concurrent/Turnstile.java | 53 ---- .../testsupport/traits/ApplicativeLaws.java | 80 +++-- .../testsupport/traits/BifunctorLaws.java | 29 +- .../java/testsupport/traits/Equivalence.java | 53 ++++ .../testsupport/traits/EquivalenceTrait.java | 33 ++ .../java/testsupport/traits/FunctorLaws.java | 30 +- .../java/testsupport/traits/MonadLaws.java | 43 +-- .../testsupport/traits/MonadReaderLaws.java | 37 +++ .../testsupport/traits/MonadWriterLaws.java | 45 +++ .../testsupport/traits/TraversableLaws.java | 61 ++-- 47 files changed, 1661 insertions(+), 434 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/MonadBase.java create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/MonadReader.java create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/MonadWriter.java create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java delete mode 100644 src/test/java/testsupport/EquatableM.java delete mode 100644 src/test/java/testsupport/concurrent/Turnstile.java create mode 100644 src/test/java/testsupport/traits/Equivalence.java create mode 100644 src/test/java/testsupport/traits/EquivalenceTrait.java create mode 100644 src/test/java/testsupport/traits/MonadReaderLaws.java create mode 100644 src/test/java/testsupport/traits/MonadWriterLaws.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ccc2186..f1fe6d8c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Changed -- ***Breaking Change***: `MonadT` is now witnessed by a parameter for better subtyping +- ***Breaking Change***: `MonadT` is now witnessed by a parameter for better subtyping, and no longer requires a common + `run` interface - ***Breaking Change***: `Applicative#zip` and derivatives evaluate from left to right now across the board. +- ***Breaking Change***: `testsupport.EquatableM` replaced with `Equivalence` - `Alter` now merely requires an `Fn1` instead of an explicit `Effect` -- `IO` now internally trampolines all forms of composition, including lazyZip; - sequencing very large iterables of IO will work, if you have the heap, and +- `IO` now internally trampolines all forms of composition, including `lazyZip`; + sequencing very large iterables of `IO` will work, if you have the heap, and retain parallelization inflection points ### Added +- `MonadError`, monads that can be thrown to and caught from, with defaults for `IO`, `Either`, `Maybe`, and `Try` - `Optic#andThen`, `Optic#compose`, and other defaults added - `Prism#andThen`, `Prism#compose` begets another `Prism` - `Prism#fromPartial` public interfaces @@ -22,11 +25,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `IO#monitorSync`, for wrapping an `IO` in a `synchronized` block on a given lock object - `IO#pin`, for pinning an `IO` to an `Executor` without yet executing it - `IO#fuse`, for fusing the fork opportunities of a given `IO` into a single linearized `IO` -- `IO#exceptionallyIO`, like `exceptionally` but recover inside another `IO` - `IO#memoize`, for memoizing an `IO` by caching its first successful result -- `MonadError`, monads that can be thrown to and caught from - `Tuple2-8#fromIterable`, for populating a `TupleN` with the first `N` elements of an `Iterable` - `Fn2#curry`, for converting an `Fn1,C>` to an `Fn2` +- `MonadBase`, an interface representing lifting infrastructure for `Monad`s +- `Lift`, an existentially-quantified lifting function for some `MonadBase` type +- `MonadReader` and `MonadWriter`, general interfaces for reading from an environment and accumulating results +- `StateT`, the `State` monad transformer +- `WriterT`, a monad transformer for an accumulation and a value +- `EquivalenceTrait`, a traitor `Trait` to make it easier to test properties of type-classes with a separate equivalence + relation ## [4.0.0] - 2019-05-20 ### Changed @@ -101,11 +109,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [3.2.0] - 2018-12-08 ### Changed -- ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to `functions.builtin.fn2` package +- ***Breaking Change***: `Difference` and `Intersection` no longer instances of `Semigroup` and moved to + `functions.builtin.fn2` package - ***Breaking Change***: `Absent` moved to `semigroup.builtin` package - ***Breaking Change***: `Effect#accept()` is now the required method to implement in the functional interface - ***Breaking Change***: `Fn0#apply()` is now the required method to implement in the functional interface -- ***Breaking Change***: `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` take the right-hand side first for more intuitive partial application +- ***Breaking Change***: `GTBy`, `GT`, `LTBy`, `LT`, `GTEBy`, `GTE`, `LTEBy`, and `LTE` take the right-hand side first + for more intuitive partial application - ***Breaking Change***: `Effect` now returns an `IO` - `RightAny` overload returns `Monoid` - monoids now all fold with respect to `foldMap` @@ -207,14 +217,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - ***Breaking Change***: `Sequence` now has two more type parameters to aid in inference - ***Breaking Change***: `Traversable#traverse` now has three more type parameters to aid in inference -- ***Breaking Change***: `Monad#zip` now forces `m a -> b` before `m a` in default `Applicative#zip` implementation; this is only breaking for types that are sensitive to computation order (the resulting values are the same) -- ***Breaking Change***: `TypeSafeKey` is now dually parametric (single parameter analog is preserved in `TypeSafeKey.Simple`) +- ***Breaking Change***: `Monad#zip` now forces `m a -> b` before `m a` in default `Applicative#zip` implementation; + this is only breaking for types that are sensitive to computation order (the resulting values are the same) +- ***Breaking Change***: `TypeSafeKey` is now dually parametric (single parameter analog is preserved in + `TypeSafeKey.Simple`) - `Bifunctor` is now a `BoundedBifunctor` where both parameter upper bounds are `Object` - `Peek2` now accepts the more general `BoundedBifunctor` - `Identity`, `Compose`, and `Const` functors all have better `toString` implementations - `Into3-8` now supports functions with parameter variance - `HListLens#tail` is now covariant in `Tail` parameter -- More functions now automatically deforest nested calls (`concat` `cons`, `cycle`, `distinct`, `drop`, `dropwhile`, `filter`, `map`, `reverse`, `snoc`, `take`, `takewhile`, `tail`) +- More functions now automatically deforest nested calls (`concat` `cons`, `cycle`, `distinct`, `drop`, `dropwhile`, + `filter`, `map`, `reverse`, `snoc`, `take`, `takewhile`, `tail`) - `Flatten` calls `Iterator#hasNext` less aggressively, allowing for better laziness - `Lens` subtypes `LensLike` - `View`/`Set`/`Over` now only require `LensLike` @@ -280,7 +293,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `CollectionLens#asSet(Function)`, a proper analog of `CollectionLens#asSet()` that uses defensive copies - `CollectionLens#asStream(Function)`, a proper analog of `CollectionLens#asStream()` that uses defensive copies - Explicitly calling attention to all unlawful lenses in their documentation -- `Peek` and `Peek2`, for "peeking" at the value contained inside any given `Functor` or `Bifunctor` with given side-effects +- `Peek` and `Peek2`, for "peeking" at the value contained inside any given `Functor` or `Bifunctor` with given + side-effects - `Trampoline` and `RecursiveResult` for modeling primitive tail-recursive functions that can be trampolined ### Removed @@ -390,7 +404,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Const` supports value equality - `partition` now only requires iterables of `CoProudct2` - `CoProductN`s receive a unification parameter, which trickles down to `Either` and `Choice`s -- `Concat` now represents a monoid for `Iterable`; previous `Concat` semigroup and monoid renamed to more appropriate `AddAll` +- `Concat` now represents a monoid for `Iterable`; previous `Concat` semigroup and monoid renamed to more appropriate + `AddAll` - `Lens` is now an instance of `Profunctor` ### Added @@ -400,14 +415,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `empty`, used to test if an Iterable is empty - `groupBy`, for folding an Iterable into a Map given a key function - `Applicative` arrives; all functors gain applicative properties -- `Traversable` arrives; `SingletonHList`, `Tuple*`, `Choice*`, `Either`, `Identity`, and `Const` gain traversable properties +- `Traversable` arrives; `SingletonHList`, `Tuple*`, `Choice*`, `Either`, `Identity`, and `Const` gain traversable + properties - `TraversableOptional` and `TraversableIterable` for adapting `Optional` and `Iterable`, respectively, to `Traversable` - `sequence` for wrapping a traversable in an applicative during traversal - `Compose`, an applicative functor that represents type-level functor composition ## [1.5.6] - 2017-02-11 ### Changed -- `CoProductN.[a-e]()` static factory methods moved to equivalent `ChoiceN` class. Coproduct interfaces now solely represent methods, no longer have anonymous implementations, and no longer require a `Functor` constraint +- `CoProductN.[a-e]()` static factory methods moved to equivalent `ChoiceN` class. Coproduct interfaces now solely + represent methods, no longer have anonymous implementations, and no longer require a `Functor` constraint ### Added - `ChoiceN` types, representing concrete coproduct implementations that are also `Functor` and `BiFunctor` @@ -461,7 +478,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [1.4] - 2016-08-08 ### Changed -- All function input values become `java.util.function` types, and all function output values remain lambda types, for better compatibility +- All function input values become `java.util.function` types, and all function output values remain lambda types, for + better compatibility ## [1.3] - 2016-07-31 ### Changed diff --git a/pom.xml b/pom.xml index 63d3a701c..c11f99dde 100644 --- a/pom.xml +++ b/pom.xml @@ -54,7 +54,7 @@ - 1.2 + 1.3.0 3.3 2.1 3.1.1 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 21fc30cfd..79ef76c2d 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 @@ -10,12 +10,15 @@ import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadWriter; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Map; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; /** * A 2-element tuple product type, implemented as a specialized HList. Supports random access. @@ -32,7 +35,7 @@ public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements Product2<_1, _2>, Map.Entry<_1, _2>, - Monad<_2, Tuple2<_1, ?>>, + MonadWriter<_1, _2, Tuple2<_1, ?>>, Bifunctor<_1, _2, Tuple2>, Traversable<_2, Tuple2<_1, ?>> { @@ -45,6 +48,22 @@ public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements _2 = tail.head(); } + /** + * {@inheritDoc} + */ + @Override + public <_3> Tuple2<_1, Tuple2<_2, _3>> listens(Fn1 fn) { + return fmap(both(id(), constantly(fn.apply(_1)))); + } + + /** + * {@inheritDoc} + */ + @Override + public Tuple2<_1, _2> censor(Fn1 fn) { + return biMapL(fn); + } + /** * {@inheritDoc} */ @@ -106,7 +125,7 @@ public Tuple2<_2, _1> invert() { */ @Override public <_2Prime> Tuple2<_1, _2Prime> fmap(Fn1 fn) { - return Monad.super.<_2Prime>fmap(fn).coerce(); + return MonadWriter.super.<_2Prime>fmap(fn).coerce(); } /** @@ -150,7 +169,7 @@ public <_2Prime> Tuple2<_1, _2Prime> pure(_2Prime _2Prime) { @Override public <_2Prime> Tuple2<_1, _2Prime> zip( Applicative, Tuple2<_1, ?>> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadWriter.super.zip(appFn).coerce(); } /** @@ -159,7 +178,7 @@ public <_2Prime> Tuple2<_1, _2Prime> zip( @Override public <_2Prime> Lazy> lazyZip( Lazy, Tuple2<_1, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_2Prime, Tuple2<_1, ?>>::coerce); + return MonadWriter.super.lazyZip(lazyAppFn).fmap(Monad<_2Prime, Tuple2<_1, ?>>::coerce); } /** @@ -167,7 +186,7 @@ public <_2Prime> Lazy> lazyZip( */ @Override public <_2Prime> Tuple2<_1, _2Prime> discardL(Applicative<_2Prime, Tuple2<_1, ?>> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadWriter.super.discardL(appB).coerce(); } /** @@ -175,7 +194,7 @@ public <_2Prime> Tuple2<_1, _2Prime> discardL(Applicative<_2Prime, Tuple2<_1, ?> */ @Override public <_2Prime> Tuple2<_1, _2> discardR(Applicative<_2Prime, Tuple2<_1, ?>> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadWriter.super.discardR(appB).coerce(); } /** 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 e1677d49f..1a1907391 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 @@ -59,7 +59,8 @@ public Maybe get(TypeSafeKey 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.")); + return get(key).orElseThrow(() -> new NoSuchElementException("Demanded value for key " + key + + ", but couldn't find one.")); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java index ce9361693..6a23e647c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java @@ -61,7 +61,7 @@ public boolean equals(Object obj) { * @return the new {@link TypeSafeKey} */ @Override - default TypeSafeKeyandThen(Iso.Simple f) { + default TypeSafeKey andThen(Iso.Simple f) { Iso.Simple composed = Iso.Simple.super.andThen(f); return new TypeSafeKey() { @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 869f1290e..c44a991ea 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -11,6 +11,8 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.internal.Runtime; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadReader; +import com.jnape.palatable.lambda.monad.MonadWriter; import java.util.function.Function; @@ -26,7 +28,8 @@ */ @FunctionalInterface public interface Fn1 extends - Monad>, + MonadReader>, + MonadWriter>, Cartesian>, Cocartesian> { @@ -83,6 +86,30 @@ default Function toFunction() { return this::apply; } + /** + * {@inheritDoc} + */ + @Override + default Fn1 local(Fn1 fn) { + return contraMap(fn); + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1> listens(Fn1 fn) { + return carry().fmap(t -> t.biMapL(fn).invert()); + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 censor(Fn1 fn) { + return a -> apply(fn.apply(a)); + } + /** * {@inheritDoc} */ @@ -116,7 +143,7 @@ default Fn1 pure(C c) { */ @Override default Fn1 zip(Applicative, Fn1> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadReader.super.zip(appFn).coerce(); } /** @@ -132,7 +159,7 @@ default Fn1 zip(Fn2 appFn) { */ @Override default Lazy> lazyZip(Lazy, Fn1>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + return MonadReader.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -140,7 +167,7 @@ default Lazy> lazyZip(Lazy Fn1 discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadReader.super.discardL(appB).coerce(); } /** @@ -148,7 +175,7 @@ default Fn1 discardL(Applicative> appB) { */ @Override default Fn1 discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadReader.super.discardR(appB).coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java new file mode 100644 index 000000000..f2b4e9c33 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java @@ -0,0 +1,37 @@ +package com.jnape.palatable.lambda.functions.specialized; + +import com.jnape.palatable.lambda.internal.Runtime; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadBase; + +/** + * Generalized, portable lifting operation for lifting a {@link Monad} into a {@link MonadBase}. + * + * @param the {@link MonadBase} to lift into + */ +@FunctionalInterface +public interface Lift> { + + > MonadBase checkedApply(Monad ga) + throws Throwable; + + default , MBA extends MonadBase> MBA apply(Monad ma) { + try { + @SuppressWarnings("unchecked") MBA MBA = (MBA) checkedApply(ma); + return MBA; + } catch (Throwable t) { + throw Runtime.throwChecked(t); + } + } + + /** + * Static method to aid inference. + * + * @param lift the {@link Lift} + * @param the {@link MonadBase} to lift into + * @return the {@link Lift} + */ + static > Lift lift(Lift lift) { + return lift; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java index 78a485bf2..9cf2125e1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Applicative.java @@ -64,11 +64,6 @@ default Lazy> lazyZip( return lazyAppFn.fmap(this::zip); } - @Override - default Applicative fmap(Fn1 fn) { - return zip(pure(fn)); - } - /** * Sequence both this Applicative and appB, discarding this Applicative's * result and returning appB. This is generally useful for sequentially performing side-effects. @@ -92,4 +87,12 @@ default Applicative discardL(Applicative appB) { default Applicative discardR(Applicative appB) { return zip(appB.fmap(constantly(id()))); } + + /** + * {@inheritDoc} + */ + @Override + default Applicative fmap(Fn1 fn) { + return zip(pure(fn)); + } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java index e3ac2783b..8c28dc54f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/Cartesian.java @@ -33,19 +33,31 @@ default Cartesian, P> carry() { return this.cartesian().contraMap(Tuple2::fill); } + /** + * {@inheritDoc} + */ @Override Cartesian diMap(Fn1 lFn, Fn1 rFn); + /** + * {@inheritDoc} + */ @Override default Cartesian diMapL(Fn1 fn) { return (Cartesian) Profunctor.super.diMapL(fn); } + /** + * {@inheritDoc} + */ @Override default Cartesian diMapR(Fn1 fn) { return (Cartesian) Profunctor.super.diMapR(fn); } + /** + * {@inheritDoc} + */ @Override default Cartesian contraMap(Fn1 fn) { return (Cartesian) Profunctor.super.contraMap(fn); diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java index 9a2c36ddc..126be9e4e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java @@ -1,20 +1,21 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadReader; +import com.jnape.palatable.lambda.monad.MonadWriter; +import com.jnape.palatable.lambda.monad.transformer.builtin.StateT; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.stateT; /** * The state {@link Monad}, useful for iteratively building up state and state-contextualized result. @@ -25,11 +26,11 @@ * @param the state type * @param the result type */ -public final class State implements Monad> { +public final class State implements MonadReader>, MonadWriter> { - private final Fn1> stateFn; + private final StateT, A> stateFn; - private State(Fn1> stateFn) { + private State(StateT, A> stateFn) { this.stateFn = stateFn; } @@ -40,7 +41,7 @@ private State(Fn1> stateFn) { * @return a {@link Tuple2} of the result and the final state. */ public Tuple2 run(S s) { - return stateFn.apply(s).into(HList::tuple); + return stateFn.>>runStateT(s).runIdentity(); } /** @@ -67,10 +68,10 @@ public S exec(S s) { * Map both the result and the final state to a new result and final state. * * @param fn the mapping function - * @param the potentially new final state type + * @param the new state type * @return the mapped {@link State} */ - public State mapState(Fn1, ? extends Product2> fn) { + public State mapState(Fn1, ? extends Tuple2> fn) { return state(s -> fn.apply(run(s))); } @@ -84,6 +85,30 @@ public State withState(Fn1 fn) { return state(s -> run(fn.apply(s))); } + /** + * {@inheritDoc} + */ + @Override + public State local(Fn1 fn) { + return state(s -> run(fn.apply(s))); + } + + /** + * {@inheritDoc} + */ + @Override + public State> listens(Fn1 fn) { + return state(s -> run(s).biMapL(both(id(), constantly(fn.apply(s))))); + } + + /** + * {@inheritDoc} + */ + @Override + public State censor(Fn1 fn) { + return local(fn); + } + /** * {@inheritDoc} */ @@ -105,7 +130,7 @@ public State pure(B b) { */ @Override public State fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadReader.super.fmap(fn).coerce(); } /** @@ -113,7 +138,7 @@ public State fmap(Fn1 fn) { */ @Override public State zip(Applicative, State> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadReader.super.zip(appFn).coerce(); } /** @@ -122,7 +147,7 @@ public State zip(Applicative, State> @Override public Lazy> lazyZip( Lazy, State>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + return MonadReader.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -130,7 +155,7 @@ public Lazy> lazyZip( */ @Override public State discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadReader.super.discardR(appB).coerce(); } /** @@ -138,7 +163,7 @@ public State discardR(Applicative> appB) { */ @Override public State discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadReader.super.discardL(appB).coerce(); } /** @@ -147,9 +172,8 @@ public State discardL(Applicative> appB) { * @param the state and result type * @return the new {@link State} instance */ - @SuppressWarnings("RedundantTypeArguments") public static State get() { - return new State<>(Tuple2::fill); + return state(Tuple2::fill); } /** @@ -161,7 +185,7 @@ public static State get() { * @return the new {@link State} instance */ public static State put(S s) { - return new State<>(constantly(tuple(UNIT, s))); + return modify(constantly(s)); } /** @@ -187,19 +211,6 @@ public static State modify(Fn1 fn) { return state(both(constantly(UNIT), fn)); } - /** - * Create a {@link State} from stateFn, a function that maps an initial state into a result and a final - * state. - * - * @param stateFn the state function - * @param the state type - * @param the result type - * @return the new {@link State} instance - */ - public static State state(Fn1> stateFn) { - return new State<>(stateFn.fmap(into(HList::tuple))); - } - /** * Create a {@link State} that returns a as its result and its initial state as its final state. * @@ -212,6 +223,19 @@ public static State state(A a) { return gets(constantly(a)); } + /** + * Create a {@link State} from stateFn, a function that maps an initial state into a result and a final + * state. + * + * @param stateFn the state function + * @param the state type + * @param the result type + * @return the new {@link State} instance + */ + public static State state(Fn1> stateFn) { + return new State<>(stateT(s -> new Identity<>(stateFn.apply(s)))); + } + /** * The canonical {@link Pure} instance for {@link State}. * diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java index 08d2f8c3f..c21d9950c 100644 --- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/GroupingIterator.java @@ -21,7 +21,7 @@ public boolean hasNext() { @Override public Iterable next() { List group = new ArrayList<>(); - int i = 0; + int i = 0; while (i++ < k && asIterator.hasNext()) group.add(asIterator.next()); return group; diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index cd3cc3fd0..fe24296f2 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -38,7 +38,7 @@ * * @param the result type */ -public abstract class IO implements Monad>, MonadError> { +public abstract class IO implements MonadError> { private IO() { } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadBase.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadBase.java new file mode 100644 index 000000000..5644b0a30 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadBase.java @@ -0,0 +1,22 @@ +package com.jnape.palatable.lambda.monad; + +/** + * A type into which a {@link Monad} is embedded whilst internally preserving the {@link Monad} structure. + * + * @param the {@link Monad} embedded in this {@link MonadBase} + * @param the carrier type + * @param the witness + */ +@SuppressWarnings("unused") +public interface MonadBase, A, MB extends MonadBase> { + + /** + * Lift a new argument {@link Monad} into this {@link MonadBase}. + * + * @param nc the argument {@link Monad} + * @param the {@link Monad} carrier type + * @param the argument {@link Monad} witness + * @return the new {@link MonadBase} + */ + > MonadBase lift(Monad nc); +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java index ad423ef75..2d88f9ba3 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java @@ -16,7 +16,7 @@ * @param the {@link Monad} witness * @param the carrier */ -public interface MonadError> extends Monad { +public interface MonadError> extends Monad { /** * Throw an error value of type E into the {@link Monad monad}. diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadReader.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadReader.java new file mode 100644 index 000000000..17fd1eddd --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadReader.java @@ -0,0 +1,83 @@ +package com.jnape.palatable.lambda.monad; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.Contravariant; +import com.jnape.palatable.lambda.functor.Profunctor; +import com.jnape.palatable.lambda.functor.builtin.Lazy; + +/** + * A monad that is capable of reading an environment R and producing a lifted value A. This + * is strictly less powerful than an {@link Fn1}, loosening the requirement on {@link Contravariant} (and therefore + * {@link Profunctor} constraints), so is more generally applicable, offering instead a {@link MonadReader#local(Fn1)} + * mechanism for modifying the environment *after* reading it but before running the effect (as opposed to + * {@link Contravariant} functors which may modify their inputs *before* running their effects, and may therefore alter + * the input types). + * + * @param the environment + * @param the output + * @param the witness + */ +public interface MonadReader> extends Monad { + + /** + * Modify this {@link MonadReader MonadReader's} environment after reading it but before running the effect. + * + * @param fn the modification function + * @return the {@link MonadReader} with a modified environment + */ + MonadReader local(Fn1 fn); + + /** + * {@inheritDoc} + */ + @Override + MonadReader flatMap(Fn1> f); + + /** + * {@inheritDoc} + */ + @Override + MonadReader pure(B b); + + /** + * {@inheritDoc} + */ + @Override + default MonadReader fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadReader zip(Applicative, MR> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Lazy> lazyZip( + Lazy, MR>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadReader discardL(Applicative appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadReader discardR(Applicative appB) { + return Monad.super.discardR(appB).coerce(); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadWriter.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadWriter.java new file mode 100644 index 000000000..906d13866 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadWriter.java @@ -0,0 +1,87 @@ +package com.jnape.palatable.lambda.monad; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; + +/** + * A {@link Monad} that is capable of writing and accumulating state alongside a value, but is not necessarily capable + * of simultaneously accessing the state and the value. + * + * @param the accumulation type + * @param the output type + * @param the witness + */ +public interface MonadWriter> extends Monad { + + /** + * Map the accumulation into a value and pair it with the current output. + * + * @param fn the mapping function + * @param the mapped output + * @return the updated {@link MonadWriter} + */ + MonadWriter, MW> listens(Fn1 fn); + + /** + * Update the accumulated state. + * + * @param fn the update function + * @return the updated {@link MonadWriter} + */ + MonadWriter censor(Fn1 fn); + + /** + * {@inheritDoc} + */ + @Override + MonadWriter flatMap(Fn1> f); + + /** + * {@inheritDoc} + */ + @Override + MonadWriter pure(B b); + + /** + * {@inheritDoc} + */ + @Override + default MonadWriter fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadWriter zip(Applicative, MW> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Lazy> lazyZip( + Lazy, MW>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Monad::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadWriter discardL(Applicative appB) { + return Monad.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default MonadWriter discardR(Applicative appB) { + return Monad.super.discardR(appB).coerce(); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java index 1f292ea81..8a68783d5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadBase; import com.jnape.palatable.lambda.monad.transformer.builtin.EitherT; import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT; import com.jnape.palatable.lambda.monad.transformer.builtin.ReaderT; /** + * The generic type representing a {@link Monad} transformer, exposing the argument {@link Monad} as a type parameter. + *

* While any two {@link Functor functors} and any two {@link Applicative applicatives} can be composed in general, the - * same is not true in general of any two {@link Monad monads}, in general. However, there exist {@link Monad monads} - * that do compose, in general, with any other {@link Monad}. When this is the case, the combination of these - * {@link Monad monads} with any other {@link Monad} can offer implementations of {@link Monad#pure pure} and + * same is not true in general of any two {@link Monad monads}. However, there exist {@link Monad monads} that do + * compose, in general, with any other {@link Monad}. When this is the case, the combination of these + * {@link Monad monads} with any other {@link Monad} can offer composed implementations of {@link Monad#pure pure} and * {@link Monad#flatMap(Fn1) flatMap} for free, simply by relying on the other {@link Monad monad's} implementation of * both, as well as their own privileged knowledge about how to merge the nested {@link Monad#flatMap(Fn1) flatMap} * call. This can be thought of as "gluing" together two {@link Monad monads}, allowing easier access to their values, @@ -26,42 +29,42 @@ * For more information, read more about * monad transformers. * - * @param the outer {@link Monad monad} - * @param the inner {@link Monad monad} - * @param the carrier type + * @param the argument {@link Monad monad} + * @param the carrier type + * @param the {@link Monad} witness + * @param the {@link MonadT} witness + * @see Monad + * @see MonadBase * @see MaybeT * @see EitherT * @see ReaderT */ -public interface MonadT, G extends Monad, A, MT extends MonadT> - extends Monad { +public interface MonadT, A, MT extends MonadT, T extends MonadT> extends + MonadBase, + Monad { /** - * Extract out the composed monad out of this transformer. - * - * @param the inferred embedded monad - * @param the inferred composed monad - * @return the composed monad + * {@inheritDoc} */ - , FGA extends Monad> FGA run(); + > MonadT lift(Monad mb); /** * {@inheritDoc} */ @Override - MonadT flatMap(Fn1> f); + MonadT flatMap(Fn1> f); /** * {@inheritDoc} */ @Override - MonadT pure(B b); + MonadT pure(B b); /** * {@inheritDoc} */ @Override - default MonadT fmap(Fn1 fn) { + default MonadT fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } @@ -69,7 +72,7 @@ default MonadT fmap(Fn1 fn) { * {@inheritDoc} */ @Override - default MonadT zip(Applicative, MT> appFn) { + default MonadT zip(Applicative, MT> appFn) { return Monad.super.zip(appFn).coerce(); } @@ -77,16 +80,16 @@ default MonadT zip(Applicative, MT> * {@inheritDoc} */ @Override - default Lazy> lazyZip( + default Lazy> lazyZip( Lazy, MT>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad::coerce); + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); } /** * {@inheritDoc} */ @Override - default MonadT discardL(Applicative appB) { + default MonadT discardL(Applicative appB) { return Monad.super.discardL(appB).coerce(); } @@ -94,7 +97,7 @@ default MonadT discardL(Applicative appB) { * {@inheritDoc} */ @Override - default MonadT discardR(Applicative appB) { + default MonadT discardR(Applicative appB) { return Monad.super.discardR(appB).coerce(); } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java index 7866eda32..2fc30f672 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; @@ -24,7 +25,7 @@ */ public final class EitherT, L, R> implements Bifunctor>, - MonadT, R, EitherT> { + MonadT, EitherT> { private final Monad, M> melr; @@ -32,12 +33,22 @@ private EitherT(Monad, M> melr) { this.melr = melr; } + /** + * Recover the full structure of the embedded {@link Monad}. + * + * @param the witnessed target type + * @return the embedded {@link Monad} + */ + public , M>> MELR runEitherT() { + return melr.coerce(); + } + /** * {@inheritDoc} */ @Override - public >, FGA extends Monad> FGA run() { - return melr.fmap(Either::coerce).coerce(); + public > EitherT lift(Monad mb) { + return EitherT.liftEitherT().apply(mb); } /** @@ -46,7 +57,7 @@ private EitherT(Monad, M> melr) { @Override public EitherT flatMap(Fn1>> f) { return eitherT(melr.flatMap(lr -> lr.match(l -> melr.pure(left(l)), - r -> f.apply(r).>coerce().run()))); + r -> f.apply(r).>coerce().runEitherT()))); } /** @@ -83,8 +94,7 @@ public Lazy> lazyZip( return new Compose<>(melr) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( maybeT.>>coerce() - .>, - Monad>, M>>run()))) + .>, M>>runEitherT()))) .fmap(compose -> eitherT(compose.getCompose())); } @@ -174,4 +184,20 @@ public EitherT checkedApply(R r) throws Throwable { } }; } + + /** + * {@link Lift} for {@link EitherT}. + * + * @param the left type + * @return the {@link Monad}lifted into {@link EitherT} + */ + public static Lift> liftEitherT() { + return new Lift>() { + @Override + public > EitherT checkedApply(Monad ga) { + return eitherT(ga.fmap(Either::right)); + } + }; + } + } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java index d800b539c..092a71fb2 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; @@ -17,7 +18,7 @@ * @param the outer {@link Monad} * @param the carrier type */ -public final class IdentityT, A> implements MonadT, A, IdentityT> { +public final class IdentityT, A> implements MonadT, IdentityT> { private final Monad, M> mia; @@ -25,12 +26,22 @@ private IdentityT(Monad, M> mia) { this.mia = mia; } + /** + * Recover the full structure of the embedded {@link Monad}. + * + * @param the witnessed target type + * @return the embedded {@link Monad} + */ + public , M>> MIA runIdentityT() { + return mia.coerce(); + } + /** * {@inheritDoc} */ @Override - public >, FGA extends Monad> FGA run() { - return mia.fmap(Identity::coerce).coerce(); + public > IdentityT lift(Monad mb) { + return liftIdentityT().apply(mb); } /** @@ -38,7 +49,7 @@ public >, FGA extends Monad> FGA run() { */ @Override public IdentityT flatMap(Fn1>> f) { - return identityT(mia.flatMap(identityA -> f.apply(identityA.runIdentity()).>coerce().run())); + return identityT(mia.flatMap(identityA -> f.apply(identityA.runIdentity()).>coerce().runIdentityT())); } /** @@ -74,8 +85,7 @@ public Lazy> lazyZip( return new Compose<>(mia) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( maybeT.>>coerce() - .>, - Monad>, M>>run()))) + .>, M>>runIdentityT()))) .fmap(compose -> identityT(compose.getCompose())); } @@ -138,4 +148,18 @@ public IdentityT checkedApply(A a) { } }; } + + /** + * {@link Lift} for {@link IdentityT}. + * + * @return the {@link Monad} lifted into {@link IdentityT} + */ + public static Lift> liftIdentityT() { + return new Lift>() { + @Override + public > IdentityT checkedApply(Monad ga) { + return identityT(ga.fmap(Identity::new)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java index 2cd3661ea..52c531c75 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java @@ -1,9 +1,9 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; @@ -19,7 +19,7 @@ * @param the outer {@link Monad} * @param the carrier type */ -public class LazyT, A> implements MonadT, A, LazyT> { +public final class LazyT, A> implements MonadT, LazyT> { private final Monad, M> mla; @@ -27,12 +27,22 @@ private LazyT(Monad, M> mla) { this.mla = mla; } + /** + * Recover the full structure of the embedded {@link Monad}. + * + * @param the witnessed target type + * @return the embedded {@link Monad} + */ + public , M>> MLA runLazyT() { + return mla.coerce(); + } + /** * {@inheritDoc} */ @Override - public >, FGA extends Monad> FGA run() { - return mla.fmap(Functor::coerce).coerce(); + public > LazyT lift(Monad mb) { + return liftLazyT().apply(mb); } /** @@ -40,8 +50,7 @@ public >, FGA extends Monad> FGA run() { */ @Override public LazyT flatMap(Fn1>> f) { - return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value()) - ., B, LazyT>>coerce().run())); + return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value()).>coerce().runLazyT())); } /** @@ -77,8 +86,7 @@ public Lazy> lazyZip( return new Compose<>(mla) .lazyZip(lazyAppFn.fmap(lazyT -> new Compose<>( lazyT.>>coerce() - .>, - Monad>, M>>run()))) + .>, M>>runLazyT()))) .fmap(compose -> lazyT(compose.getCompose())); } @@ -141,4 +149,18 @@ public LazyT checkedApply(A a) { } }; } + + /** + * {@link Lift} for {@link LazyT}. + * + * @return the {@link Monad} lifted into {@link LazyT} + */ + public static Lift> liftLazyT() { + return new Lift>() { + @Override + public > LazyT checkedApply(Monad ga) { + return lazyT(ga.fmap(Lazy::lazy)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index 57cc831ae..b105175ae 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; @@ -21,7 +22,7 @@ * @param the outer {@link Monad} * @param the carrier type */ -public final class MaybeT, A> implements MonadT, A, MaybeT> { +public final class MaybeT, A> implements MonadT, MaybeT> { private final Monad, M> mma; @@ -29,12 +30,22 @@ private MaybeT(Monad, M> mma) { this.mma = mma; } + /** + * Recover the full structure of the embedded {@link Monad}. + * + * @param the witnessed target type + * @return the embedded {@link Monad} + */ + public , M>> MMA runMaybeT() { + return mma.coerce(); + } + /** * {@inheritDoc} */ @Override - public >, FGA extends Monad> FGA run() { - return mma.fmap(Applicative::coerce).coerce(); + public > MaybeT lift(Monad mb) { + return liftMaybeT().apply(mb); } /** @@ -70,7 +81,7 @@ public Lazy> lazyZip( return new Compose<>(mma) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( maybeT.>>coerce() - .>, Monad>, M>>run()))) + .>, M>>runMaybeT()))) .fmap(compose -> maybeT(compose.getCompose())); } @@ -81,7 +92,7 @@ public Lazy> lazyZip( public MaybeT flatMap(Fn1>> f) { return maybeT(mma.flatMap(ma -> ma .match(constantly(mma.pure(nothing())), - a -> f.apply(a).>coerce().run()))); + a -> f.apply(a).>coerce().runMaybeT()))); } /** @@ -145,4 +156,19 @@ public MaybeT checkedApply(A a) { } }; } + + /** + * {@link Lift} for {@link MaybeT}. + * s + * + * @return the {@link Monad} lifted into {@link MaybeT} + */ + public static Lift> liftMaybeT() { + return new Lift>() { + @Override + public > MaybeT checkedApply(Monad ga) { + return maybeT(ga.fmap(Maybe::just)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index 227bd1df2..3e496e2c9 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -2,13 +2,16 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cartesian; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadReader; import com.jnape.palatable.lambda.monad.transformer.MonadT; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; @@ -21,23 +24,25 @@ * @param the embedded output type */ public final class ReaderT, A> implements - MonadT, M, A, ReaderT>, - Cartesian> { + MonadReader>, + Cartesian>, + MonadT, ReaderT> { - private final Fn1> fn; + private final Fn1> f; - private ReaderT(Fn1> fn) { - this.fn = fn; + private ReaderT(Fn1> f) { + this.f = f; } /** * Run the computation represented by this {@link ReaderT}. * - * @param r the input - * @return the {¬@link Monad monadic} embedding {@link Monad}<A, M> + * @param r the input + * @param the witnessed target type + * @return the embedded {@link Monad} */ public > MA runReaderT(R r) { - return fn.apply(r).coerce(); + return f.apply(r).coerce(); } /** @@ -58,8 +63,16 @@ public , N extends Monad, B> ReaderT mapRe * {@inheritDoc} */ @Override - public , FGA extends Monad>> FGA run() { - return Fn1.fn1(r -> runReaderT(r).coerce()).coerce(); + public ReaderT local(Fn1 fn) { + return contraMap(fn); + } + + /** + * {@inheritDoc} + */ + @Override + public > ReaderT lift(Monad mb) { + return ReaderT.liftReaderT().apply(mb); } /** @@ -91,7 +104,7 @@ public ReaderT fmap(Fn1 fn) { */ @Override public ReaderT zip(Applicative, ReaderT> appFn) { - return readerT(r -> runReaderT(r).zip(appFn.>>coerce().runReaderT(r))); + return readerT(r -> f.apply(r).zip(appFn.>>coerce().runReaderT(r))); } /** @@ -176,7 +189,7 @@ public ReaderT> carry() { * @param the embedded output type * @return the {@link ReaderT} */ - public static , A> ReaderT readerT(Fn1> fn) { + static , A> ReaderT readerT(Fn1> fn) { return new ReaderT<>(fn); } @@ -196,4 +209,19 @@ public ReaderT checkedApply(A a) { } }; } + + /** + * {@link Lift} for {@link ReaderT}. + * + * @param the environment type + * @return the {@link Monad} lifted into {@link ReaderT} + */ + public static Lift> liftReaderT() { + return new Lift>() { + @Override + public > ReaderT checkedApply(Monad ga) { + return readerT(constantly(ga)); + } + }; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java new file mode 100644 index 000000000..b48db7887 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java @@ -0,0 +1,298 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Lift; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.functor.builtin.State; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadReader; +import com.jnape.palatable.lambda.monad.MonadWriter; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; + + +/** + * The {@link State} {@link MonadT monad transformer}. + * + * @param the state type + * @param the {@link Monad monadic embedding} + * @param the result type + * @see State + */ +public final class StateT, A> implements + MonadT, StateT>, + MonadReader>, + MonadWriter> { + + private final Fn1, M>> stateFn; + + private StateT(Fn1, M>> stateFn) { + this.stateFn = stateFn; + } + + /** + * Run the stateful computation embedded in the {@link Monad}, returning a {@link Tuple2} of the result and the + * final state. + * + * @param s the initial state + * @param the inferred {@link Monad} result + * @return a {@link Tuple2} of the result and the final state. + */ + public , M>> MAS runStateT(S s) { + return stateFn.apply(s).coerce(); + } + + /** + * Run the stateful computation embedded in the {@link Monad}, returning the result. + * + * @param s the initial state + * @param the inferred {@link Monad} result + * @return the result + */ + public > MA evalT(S s) { + return runStateT(s).fmap(Tuple2::_1).coerce(); + } + + /** + * Run the stateful computation embedded in the {@link Monad}, returning the final state. + * + * @param s the initial state + * @param the inferred {@link Monad} result + * @return the final state + */ + public > MS execT(S s) { + return runStateT(s).fmap(Tuple2::_2).coerce(); + } + + /** + * Map both the result and the final state to a new result and final state inside the {@link Monad}. + * + * @param fn the mapping function + * @param the new {@link Monad monadic embedding} for this {@link StateT} + * @param the new state type + * @return the mapped {@link StateT} + */ + public , B> StateT mapStateT( + Fn1, M>, ? extends Monad, N>> fn) { + return stateT(s -> fn.apply(runStateT(s))); + } + + /** + * Map the final state to a new final state inside the same {@link Monad monadic effect} using the provided + * function. + * + * @param fn the state-mapping function + * @return the mapped {@link StateT} + */ + public StateT withStateT(Fn1> fn) { + return modify(fn).flatMap(constantly(this)); + } + + /** + * {@inheritDoc} + */ + @Override + public StateT> listens(Fn1 fn) { + return mapStateT(mas -> mas.fmap(t -> t.into((a, s) -> tuple(tuple(a, fn.apply(s)), s)))); + } + + /** + * {@inheritDoc} + */ + @Override + public StateT censor(Fn1 fn) { + return local(fn); + } + + /** + * {@inheritDoc} + */ + @Override + public StateT local(Fn1 fn) { + return stateT(s -> runStateT(fn.apply(s))); + } + + /** + * {@inheritDoc} + */ + @Override + public StateT flatMap(Fn1>> f) { + return stateT(s -> runStateT(s).flatMap(into((a, s_) -> f.apply(a).>coerce().runStateT(s_)))); + } + + /** + * {@inheritDoc} + */ + @Override + public StateT pure(B b) { + return stateT(s -> runStateT(s).pure(tuple(b, s))); + } + + /** + * {@inheritDoc} + */ + @Override + public StateT fmap(Fn1 fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public StateT zip(Applicative, StateT> appFn) { + return stateT(s -> runStateT(s) + .zip(appFn.>>coerce() + .runStateT(s) + .fmap(Tuple2::_1) + .fmap(f -> t -> t.biMapL(f)))); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, StateT>> lazyAppFn) { + return MonadT.super.lazyZip(lazyAppFn).fmap(MonadT, StateT>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + public StateT discardL(Applicative> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public StateT discardR(Applicative> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public > StateT lift(Monad mb) { + return stateT(s -> mb.fmap(b -> tuple(b, s))); + } + + /** + * Given a {@link Pure pure} construction of some {@link Monad}, produce a {@link StateT} that equates its output + * with its state. + * + * @param pureM the {@link Pure pure} construction + * @param the state and value type + * @param the {@link Monad} embedding + * @return the {@link StateT} + */ + @SuppressWarnings("RedundantTypeArguments") + public static > StateT get(Pure pureM) { + return gets(pureM::>apply); + } + + /** + * Given a function that produces a value inside a {@link Monad monadic effect} from a state, produce a + * {@link StateT} that simply passes its state to the function and applies it. + * + * @param fn the function + * @param the state type + * @param the{@link Monad} embedding + * @param the value type + * @return the {@link StateT} + */ + public static , A> StateT gets(Fn1> fn) { + return stateT(s -> fn.apply(s).fmap(a -> tuple(a, s))); + } + + /** + * Lift a function that makes a stateful modification inside an {@link Monad} into {@link StateT}. + * + * @param updateFn the update function + * @param the state type + * @param the {@link Monad} embedding + * @return the {@link StateT} + */ + public static > StateT modify(Fn1> updateFn) { + return stateT(s -> updateFn.apply(s).fmap(tupler(UNIT))); + } + + /** + * Lift a {@link Monad monadic state} into {@link StateT}. + * + * @param ms the state + * @param the state type + * @param the {@link Monad} embedding + * @return the {@link StateT} + */ + public static > StateT put(Monad ms) { + return modify(constantly(ms)); + } + + /** + * Lift a {@link Monad monadic value} into {@link StateT}. + * + * @param ma the value + * @param the state type + * @param the {@link Monad} embedding + * @param the result type + * @return the {@link StateT} + */ + public static , A> StateT stateT(Monad ma) { + return gets(constantly(ma)); + } + + /** + * Lift a state-sensitive {@link Monad monadically embedded} computation into {@link StateT}. + * + * @param stateFn the stateful operation + * @param the state type + * @param the {@link Monad} embedding + * @param the result type + * @return the {@link StateT} + */ + public static , A> StateT stateT( + Fn1, M>> stateFn) { + return new StateT<>(stateFn); + } + + /** + * The canonical {@link Pure} instance for {@link StateT}. + * + * @param pureM the argument {@link Monad} {@link Pure} + * @param the state type + * @param the argument {@link Monad} witness + * @return the {@link Pure} instance + */ + public static > Pure> pureStateT(Pure pureM) { + return new Pure>() { + @Override + public StateT checkedApply(A a) throws Throwable { + return stateT(pureM.>apply(a)); + } + }; + } + + /** + * {@link Lift} for {@link StateT}. + * + * @param the state type + * @return the {@link Monad} lifted into {@link StateT} + */ + public static Lift> liftStateT() { + return StateT::stateT; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java new file mode 100644 index 000000000..d661e1f69 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java @@ -0,0 +1,202 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.Lift; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadWriter; +import com.jnape.palatable.lambda.monad.transformer.MonadT; +import com.jnape.palatable.lambda.monoid.Monoid; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; + +/** + * A strict transformer for a {@link Tuple2} holding a value and an accumulation. + * + * @param the accumulation type + * @param the {@link Monad monadic embedding} + * @param the result type + */ +public final class WriterT, A> implements + MonadWriter>, + MonadT, WriterT> { + + private final Fn1, ? extends Monad, M>> writerFn; + + private WriterT(Fn1, ? extends Monad, M>> writerFn) { + this.writerFn = writerFn; + } + + /** + * Given a {@link Monoid} for the accumulation, run the computation represented by this {@link WriterT} inside the + * {@link Monad monadic effect}, accumulate the written output in terms of the {@link Monoid}, and produce the + * accumulation and the result inside the {@link Monad}. + * + * @param monoid the accumulation {@link Monoid} + * @param the inferred {@link Monad} result + * @return the accumulation with the result + */ + public , M>> MAW runWriterT(Monoid monoid) { + return writerFn.apply(monoid).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public WriterT> listens(Fn1 fn) { + return new WriterT<>(writerFn.fmap(m -> m.fmap(into((a, w) -> both(both(constantly(a), fn), id(), w))))); + } + + /** + * {@inheritDoc} + */ + @Override + public WriterT censor(Fn1 fn) { + return new WriterT<>(writerFn.fmap(mt -> mt.fmap(t -> t.fmap(fn)))); + } + + /** + * {@inheritDoc} + */ + @Override + public > WriterT lift(Monad mb) { + return WriterT.liftWriterT().apply(mb); + } + + /** + * {@inheritDoc} + */ + @Override + public WriterT fmap(Fn1 fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public WriterT pure(B b) { + return new WriterT<>(m -> runWriterT(m).pure(tuple(b, m.identity()))); + } + + /** + * {@inheritDoc} + */ + @Override + public WriterT flatMap(Fn1>> f) { + return new WriterT<>(monoid -> writerFn.apply(monoid) + .flatMap(into((a, w) -> f.apply(a).>coerce().runWriterT(monoid) + .fmap(t -> t.fmap(monoid.apply(w)))))); + } + + /** + * {@inheritDoc} + */ + @Override + public WriterT zip(Applicative, WriterT> appFn) { + return new WriterT<>(monoid -> runWriterT(monoid) + .zip(appFn.>>coerce().runWriterT(monoid) + .fmap(into((f, y) -> into((a, x) -> tuple(f.apply(a), monoid.apply(x, y))))))); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, WriterT>> lazyAppFn) { + return lazyAppFn.fmap(this::zip); + } + + /** + * {@inheritDoc} + */ + @Override + public WriterT discardL(Applicative> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public WriterT discardR(Applicative> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + /** + * Lift an accumulation embedded in a {@link Monad} into a {@link WriterT}. + * + * @param mw the accumulation inside a {@link Monad} + * @param the accumulation type + * @param the {@link Monad} type + * @return the {@link WriterT} + */ + public static > WriterT tell(Monad mw) { + return writerT(mw.fmap(tupler(UNIT))); + } + + /** + * Lift a value embedded in a {@link Monad} into a {@link WriterT}. + * + * @param ma the value inside a {@link Monad} + * @param the accumulation type + * @param the {@link Monad} type + * @param the value type + * @return the {@link WriterT} + */ + public static , A> WriterT listen(Monad ma) { + return new WriterT<>(monoid -> ma.fmap(a -> tuple(a, monoid.identity()))); + } + + /** + * Lift a value and an accumulation embedded in a {@link Monad} into a {@link WriterT}. + * + * @param mwa the value and accumulation inside a {@link Monad} + * @param the accumulation type + * @param the {@link Monad} type + * @param the value type + * @return the {@link WriterT} + */ + public static , A> WriterT writerT(Monad, M> mwa) { + return new WriterT<>(constantly(mwa)); + } + + /** + * The canonical {@link Pure} instance for {@link WriterT}. + * + * @param pureM the argument {@link Monad} {@link Pure} + * @param the accumulation type + * @param the argument {@link Monad} witness + * @return the {@link Pure} instance + */ + public static > Pure> pureWriterT(Pure pureM) { + return new Pure>() { + @Override + public WriterT checkedApply(A a) throws Throwable { + return listen(pureM.>apply(a)); + } + }; + } + + /** + * {@link Lift} for {@link WriterT}. + * + * @param the accumulated type + * @return the {@link Monad} lifted into {@link WriterT} + */ + public static Lift> liftWriterT() { + return WriterT::listen; + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index b603261a0..766344de3 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -4,10 +4,12 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadReaderLaws; +import testsupport.traits.MonadWriterLaws; import java.util.function.Function; @@ -20,13 +22,18 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.ReduceLeft.reduceLeft; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; +import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class Fn1Test { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, ?> testSubject() { - return new EquatableM<>(fn1(Integer::parseInt), f -> f.apply("1")); + @TestTraits({FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadReaderLaws.class, + MonadWriterLaws.class}) + public Equivalence> testSubject() { + return equivalence(fn1(Integer::parseInt), f -> f.apply("1")); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java index 5f71142f9..0699d4f5b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java @@ -5,8 +5,8 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -19,13 +19,14 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static testsupport.Constants.STACK_EXPLODING_NUMBER; +import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class LazyTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, Integer> testSubject() { - return new EquatableM<>(lazy(0), Lazy::value); + public Equivalence> testSubject() { + return equivalence(lazy(0), Lazy::value); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java index 9212246b8..2f79ffe85 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java @@ -5,8 +5,8 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -18,16 +18,17 @@ import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.lang.Integer.parseInt; import static org.junit.Assert.assertEquals; +import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class MarketTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public Subjects, String>> testSubject() { + public Subjects>> testSubject() { Market market = new Market<>(id(), str -> trying(() -> parseInt(str), constantly(str))); - return subjects(new EquatableM<>(market, m -> both(m.bt(), m.sta(), "123")), - new EquatableM<>(market, m -> both(m.bt(), m.sta(), "foo"))); + return subjects(equivalence(market, m -> both(m.bt(), m.sta(), "123")), + equivalence(market, m -> both(m.bt(), m.sta(), "foo"))); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java index 0dded6598..1a22282b6 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java @@ -1,30 +1,35 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadReaderLaws; +import testsupport.traits.MonadWriterLaws; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.adt.product.Product2.product; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static org.junit.Assert.assertEquals; +import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class StateTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, Unit> testSubject() { - return new EquatableM<>(State.get(), state -> state.run(UNIT).into(HList::tuple)); + @TestTraits({FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadReaderLaws.class, + MonadWriterLaws.class}) + public Equivalence> testSubject() { + return equivalence(State.gets(String::length), s -> s.run("foo")); } @Test @@ -62,7 +67,7 @@ public void modify() { @Test public void state() { assertEquals(tuple(1, UNIT), State.state(1).run(UNIT)); - assertEquals(tuple(1, -1), State.state(x -> product(x + 1, x - 1)).run(0)); + assertEquals(tuple(1, -1), State.state(x -> tuple(x + 1, x - 1)).run(0)); } @Test @@ -87,7 +92,7 @@ public void withState() { @Test public void mapState() { - State modified = State.get().mapState(into((a, s) -> product(a + 1, s + 2))); + State modified = State.get().mapState(into((a, s) -> tuple(a + 1, s + 2))); assertEquals(tuple(1, 2), modified.run(0)); } diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index b3bda711d..b6abb76de 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -10,8 +10,8 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; -import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -56,6 +56,7 @@ import static org.junit.Assert.fail; import static testsupport.Constants.STACK_EXPLODING_NUMBER; import static testsupport.assertion.MonadErrorAssert.assertLawsEq; +import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class IOTest { @@ -63,14 +64,14 @@ public class IOTest { public @Rule ExpectedException thrown = ExpectedException.none(); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, Integer> testSubject() { - return new EquatableM<>(io(1), IO::unsafePerformIO); + public Equivalence> testSubject() { + return equivalence(io(1), IO::unsafePerformIO); } @Test public void monadError() { - assertLawsEq(subjects(new EquatableM<>(IO.throwing(new IllegalStateException("a")), IO::unsafePerformIO), - new EquatableM<>(io(1), IO::unsafePerformIO)), + assertLawsEq(subjects(equivalence(IO.throwing(new IllegalStateException("a")), IO::unsafePerformIO), + equivalence(io(1), IO::unsafePerformIO)), new IOException("bar"), e -> io(e.getMessage().length())); } diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java index a56aac135..b709f7957 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java @@ -6,23 +6,24 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadReaderLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.monad.transformer.builtin.ReaderT.readerT; import static org.junit.Assert.assertEquals; +import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class ReaderTTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, ?>, Integer> testSubject() { - return new EquatableM<>(readerT(Identity::new), - readerT -> readerT.runReaderT(1)); + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadReaderLaws.class}) + public Equivalence, Integer>> testSubject() { + return equivalence(readerT(Identity::new), readerT -> readerT.runReaderT(1)); } @Test @@ -33,6 +34,14 @@ public void profunctor() { .runReaderT("123")); } + @Test + public void local() { + assertEquals(new Identity<>(2), + ReaderT., Integer>readerT(Identity::new) + .local(x -> x + 1) + .runReaderT(1)); + } + @Test public void mapReaderT() { assertEquals(just(3), diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java new file mode 100644 index 000000000..18efdf5c5 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java @@ -0,0 +1,119 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; +import testsupport.traits.MonadReaderLaws; +import testsupport.traits.MonadWriterLaws; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; +import static org.junit.Assert.assertEquals; +import static testsupport.traits.Equivalence.equivalence; + +@RunWith(Traits.class) +public class StateTTest { + + @TestTraits({FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadReaderLaws.class, + MonadWriterLaws.class}) + public Equivalence, Integer>> testReader() { + return equivalence(StateT.gets(s -> new Identity<>(s.length())), s -> s.runStateT("foo")); + } + + @Test + public void evalAndExec() { + StateT, Integer> stateT = + StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_"))); + + assertEquals(new Identity<>("__"), stateT.execT("_")); + assertEquals(new Identity<>(1), stateT.evalT("_")); + } + + @Test + public void mapStateT() { + StateT, Integer> stateT = + StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_"))); + assertEquals(just(tuple(4, "ABC_")), + stateT.mapStateT(id -> id.>>coerce() + .runIdentity() + .into((x, str) -> just(tuple(x + 1, str.toUpperCase())))) + .>>runStateT("abc")); + } + + @Test + public void zipping() { + assertEquals(new Identity<>(tuple(4, "final state: FOO")), + StateT.>modify(s -> new Identity<>(s.toUpperCase())) + .discardL(StateT.gets(s -> new Identity<>(s.length()))) + .flatMap(x -> StateT.stateT(s -> new Identity<>(tuple(x + 1, "final state: " + s)))) + .>>runStateT("foo")); + } + + @Test + public void withStateT() { + StateT, Integer> stateT = + StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_"))); + assertEquals(new Identity<>(tuple(3, "ABC_")), + stateT.withStateT(str -> new Identity<>(str.toUpperCase())).runStateT("abc")); + } + + @Test + public void get() { + assertEquals(new Identity<>(tuple("state", "state")), + StateT.>get(pureIdentity()).runStateT("state")); + } + + @Test + public void gets() { + assertEquals(new Identity<>(tuple(5, "state")), + StateT., Integer>gets(s -> new Identity<>(s.length())).runStateT("state")); + } + + @Test + public void put() { + assertEquals(new Identity<>(tuple(UNIT, 1)), StateT.put(new Identity<>(1)).runStateT(0)); + } + + @Test + public void modify() { + assertEquals(new Identity<>(tuple(UNIT, 1)), + StateT.>modify(x -> new Identity<>(x + 1)).runStateT(0)); + } + + @Test + public void stateT() { + assertEquals(new Identity<>(tuple(0, "_")), + StateT., Integer>stateT(new Identity<>(0)).runStateT("_")); + assertEquals(new Identity<>(tuple(1, "_1")), + StateT., Integer>stateT(s -> new Identity<>(tuple(s.length(), s + "1"))) + .runStateT("_")); + } + + @Test + public void staticPure() { + assertEquals(new Identity<>(tuple(1, "foo")), + StateT.>pureStateT(pureIdentity()) + ., Integer>>apply(1) + .>>runStateT("foo")); + } + + @Test + public void staticLift() { + assertEquals(new Identity<>(tuple(1, "foo")), + StateT.liftStateT()., StateT, Integer>>apply(new Identity<>(1)) + .>>runStateT("foo")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java new file mode 100644 index 000000000..26a571297 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java @@ -0,0 +1,66 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; +import testsupport.traits.MonadWriterLaws; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; +import static com.jnape.palatable.lambda.monad.transformer.builtin.WriterT.writerT; +import static com.jnape.palatable.lambda.monoid.builtin.Join.join; +import static org.junit.Assert.assertEquals; +import static testsupport.traits.Equivalence.equivalence; + +@RunWith(Traits.class) +public class WriterTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadWriterLaws.class}) + public Equivalence, Integer>> testSubject() { + return equivalence(writerT(new Identity<>(tuple(2, ""))), writerT -> writerT.runWriterT(join())); + } + + @Test + public void accumulationUsesProvidedMonoid() { + Identity> result = writerT(new Identity<>(tuple(1, "foo"))) + .discardR(WriterT.tell(new Identity<>("bar"))) + .flatMap(x -> writerT(new Identity<>(tuple(x + 1, "baz")))) + .runWriterT(join()); + + assertEquals(new Identity<>(tuple(2, "foobarbaz")), result); + } + + @Test + public void tell() { + assertEquals(new Identity<>(tuple(UNIT, "")), + WriterT.tell(new Identity<>("")).runWriterT(join())); + } + + @Test + public void listen() { + assertEquals(new Identity<>(tuple(1, "")), + WriterT., Integer>listen(new Identity<>(1)).runWriterT(join())); + } + + @Test + public void staticPure() { + WriterT, Integer> apply = WriterT.>pureWriterT(pureIdentity()).apply(1); + assertEquals(new Identity<>(tuple(1, "")), + apply.runWriterT(join())); + } + + @Test + public void staticLift() { + WriterT, Integer> apply = WriterT.liftWriterT().apply(new Identity<>(1)); + assertEquals(new Identity<>(tuple(1, "")), + apply.runWriterT(join())); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java index 69174c801..48ab32b73 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java @@ -5,8 +5,8 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -19,6 +19,7 @@ import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; +import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class IsoTest { @@ -27,8 +28,8 @@ public class IsoTest { iso(Integer::parseInt, dbl -> dbl.toString().chars().mapToObj(x -> (char) x).collect(toList())); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, List> testSubject() { - return new EquatableM<>(ISO, iso -> view(iso, "123")); + public Equivalence, Integer, Double>> testSubject() { + return equivalence(ISO, iso -> view(iso, "123")); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java index f5b1cbf2a..60821aed0 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java @@ -9,8 +9,8 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -32,6 +32,7 @@ import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static org.junit.Assert.assertEquals; +import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class LensTest { @@ -42,9 +43,8 @@ public class LensTest { LENS = lens(xs -> xs.get(0), (xs, i) -> singleton(i)); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, ?, Integer, String>, List> testSubject() { - return new EquatableM<>(lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s))), - lens -> view(lens, emptyMap())); + public Equivalence, List, Integer, String>> testSubject() { + return equivalence(lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s))), lens -> view(lens, emptyMap())); } @Test @@ -97,9 +97,9 @@ public void andThenComposesInReverse() { @Test public void bothSplitsFocusBetweenLenses() { - Lens firstChar = simpleLens(s -> s.charAt(0), (s, c) -> c + s.substring(1)); - Lens length = simpleLens(String::length, (s, k) -> s.substring(0, k)); - Lens, Tuple2> both = both(firstChar, length); + Lens firstChar = simpleLens(s -> s.charAt(0), (s, c) -> c + s.substring(1)); + Lens length = simpleLens(String::length, (s, k) -> s.substring(0, k)); + Lens, Tuple2> both = both(firstChar, length); assertEquals(tuple('a', 3), view(both, "abc")); assertEquals("zb", set(both, tuple('z', 2), "abc")); @@ -107,7 +107,7 @@ public void bothSplitsFocusBetweenLenses() { @Test public void bothForSimpleLenses() { - Lens.Simple stringToInt = simpleLens(Integer::parseInt, (s, i) -> s + i.toString()); + Lens.Simple stringToInt = simpleLens(Integer::parseInt, (s, i) -> s + i.toString()); Lens.Simple stringToChar = simpleLens(s -> s.charAt(0), (s, c) -> s + c.toString()); assertEquals(tuple(3, '3'), view(both(stringToInt, stringToChar), "3")); diff --git a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java index e86080f75..ab36ff51f 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java @@ -7,8 +7,8 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.EquatableM; import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; @@ -27,6 +27,7 @@ import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static testsupport.assertion.PrismAssert.assertPrismLawfulness; +import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class PrismTest { @@ -34,9 +35,9 @@ public class PrismTest { private static final Fn1 PARSE_INT = Fn1.fn1(Integer::parseInt); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, String> testSubject() { - return new EquatableM<>(Prism.fromPartial(Integer::parseInt, Object::toString), - prism -> matching(prism, "foo")); + public Equivalence> testSubject() { + return equivalence(Prism.fromPartial(Integer::parseInt, Object::toString), + prism -> matching(prism, "foo")); } @Test diff --git a/src/test/java/testsupport/EquatableM.java b/src/test/java/testsupport/EquatableM.java deleted file mode 100644 index a812df222..000000000 --- a/src/test/java/testsupport/EquatableM.java +++ /dev/null @@ -1,79 +0,0 @@ -package testsupport; - -import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functor.Applicative; -import com.jnape.palatable.lambda.functor.builtin.Lazy; -import com.jnape.palatable.lambda.monad.Monad; - -import java.util.Objects; - -public final class EquatableM, A> implements Monad> { - - private final Monad ma; - private final Fn1 equatable; - - public EquatableM(Monad ma, Fn1 equatable) { - this.ma = ma; - this.equatable = equatable; - } - - public EquatableM with(Fn1, ? extends Monad> fn) { - return new EquatableM<>(fn.apply(ma), equatable); - } - - public EquatableM swap(Monad mb) { - return new EquatableM<>(mb, equatable); - } - - @Override - public EquatableM flatMap(Fn1>> f) { - return new EquatableM<>(ma.flatMap(f.fmap(x -> x.>coerce().ma)), equatable); - } - - @Override - public EquatableM pure(B b) { - return new EquatableM<>(ma.pure(b), equatable); - } - - @Override - public EquatableM fmap(Fn1 fn) { - return new EquatableM<>(ma.fmap(fn), equatable); - } - - @Override - public EquatableM zip(Applicative, EquatableM> appFn) { - return new EquatableM<>(ma.zip(appFn.>>coerce().ma), equatable); - } - - @Override - public Lazy> lazyZip( - Lazy, EquatableM>> lazyAppFn) { - return ma.lazyZip(lazyAppFn.fmap(eqF -> eqF.>>coerce().ma)) - .fmap(mb -> new EquatableM<>(mb, equatable)); - } - - @Override - public EquatableM discardL(Applicative> appB) { - return new EquatableM<>(ma.discardL(appB.>coerce().ma), equatable); - } - - @Override - public EquatableM discardR(Applicative> appB) { - return new EquatableM<>(ma.discardR(appB.>coerce().ma), equatable); - } - - @Override - @SuppressWarnings("unchecked") - public boolean equals(Object other) { - if (other instanceof EquatableM) { - EquatableM that = (EquatableM) other; - return Objects.equals(equatable.apply((M) ma), that.equatable.apply((M) that.ma)); - } - return false; - } - - @Override - public int hashCode() { - return super.hashCode(); - } -} diff --git a/src/test/java/testsupport/assertion/MonadErrorAssert.java b/src/test/java/testsupport/assertion/MonadErrorAssert.java index 399be85fb..a4cc2e423 100644 --- a/src/test/java/testsupport/assertion/MonadErrorAssert.java +++ b/src/test/java/testsupport/assertion/MonadErrorAssert.java @@ -5,45 +5,40 @@ import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.MonadError; import com.jnape.palatable.traitor.framework.Subjects; -import testsupport.EquatableM; +import testsupport.traits.Equivalence; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static testsupport.traits.Equivalence.equivalence; public final class MonadErrorAssert { private MonadErrorAssert() { } - public static > void assertLaws( - Subjects> subjects, + public static , MA extends MonadError> void assertLaws( + Subjects subjects, E e, - Fn1> recovery) { - - subjects.forEach(subject -> throwCatch(subject, e, recovery) + Fn1 recovery) { + subjects.forEach(subject -> throwCatch(equivalence(subject, id()), e, recovery) .peek(failures -> IO.throwing(new AssertionError("MonadError law failures\n\n" + failures)))); } - public static > void assertLawsEq( - Subjects> subjects, + public static , MA extends MonadError> void assertLawsEq( + Subjects> subjects, E e, - Fn1> recovery) { + Fn1 recovery) { subjects.forEach(subject -> throwCatch(subject, e, recovery) .peek(failures -> IO.throwing(new AssertionError("MonadError law failures\n\n" + failures)))); } - private static > Maybe throwCatch( - MonadError monadError, - E e, - Fn1> recovery) { - return throwCatch(new EquatableM<>(monadError, x -> x), e, recovery); - } - - private static > Maybe throwCatch( - EquatableM equatable, + private static , MA extends MonadError> Maybe throwCatch( + Equivalence equivalence, E e, - Fn1> recovery) { - EquatableM eq = equatable.with(ma -> ma.>coerce().throwError(e).catchError(recovery)); - return eq.equals(eq.swap(recovery.apply(e))) + Fn1 recovery) { + return equivalence.invMap(ma -> ma.throwError(e).catchError(recovery).coerce()) + .equals(equivalence.swap(recovery.apply(e))) ? Maybe.nothing() - : Maybe.just("ThrowCatch failed: " + equatable + ".throwError(" + e + ")" + + : Maybe.just("ThrowCatch failed: " + equivalence + ".throwError(" + e + ")" + ".catchError(recoveryFn) /= recovery.apply(" + e + ")"); } } diff --git a/src/test/java/testsupport/concurrent/Turnstile.java b/src/test/java/testsupport/concurrent/Turnstile.java deleted file mode 100644 index 96da97d30..000000000 --- a/src/test/java/testsupport/concurrent/Turnstile.java +++ /dev/null @@ -1,53 +0,0 @@ -package testsupport.concurrent; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; - -import static java.lang.Thread.currentThread; -import static java.util.concurrent.locks.LockSupport.park; -import static java.util.concurrent.locks.LockSupport.unpark; -import static java.util.stream.StreamSupport.stream; - -public final class Turnstile { - - private final int parties; - private final BlockingQueue arrivals; - - public Turnstile(int parties) { - this.parties = parties; - arrivals = new ArrayBlockingQueue<>(parties); - } - - public void arrive() { - synchronized (this) { - arrivals.add(currentThread()); - if (arrivals.size() == parties) { - allowThrough(parties); - return; - } - } - park(); - } - - public void allowAllThrough() { - allowThrough(arrivals.size()); - } - - @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - private void allowThrough(int parked) { - Thread currentThread = currentThread(); - Collection allowedThrough = new ArrayList<>(); - arrivals.drainTo(allowedThrough, parked); - stream(allowedThrough.spliterator(), false) - .filter(t -> !t.equals(currentThread)) - .forEach(t -> { - unpark(t); - try { - t.join(); - } catch (InterruptedException ignored) { - } - }); - } -} diff --git a/src/test/java/testsupport/traits/ApplicativeLaws.java b/src/test/java/testsupport/traits/ApplicativeLaws.java index 1d5c0904f..05278e84d 100644 --- a/src/test/java/testsupport/traits/ApplicativeLaws.java +++ b/src/test/java/testsupport/traits/ApplicativeLaws.java @@ -5,7 +5,6 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; -import com.jnape.palatable.traitor.traits.Trait; import java.util.Random; @@ -16,13 +15,18 @@ import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static java.util.Arrays.asList; -public class ApplicativeLaws> implements Trait> { +public class ApplicativeLaws> implements EquivalenceTrait> { @Override - public void test(Applicative applicative) { + public Class> type() { + return Applicative.class; + } + + @Override + public void test(Equivalence> equivalence) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap( - f -> f.apply(applicative), + .>, Maybe>>foldMap( + f -> f.apply(equivalence), asList(this::testIdentity, this::testComposition, this::testHomomorphism, @@ -32,76 +36,68 @@ public void test(Applicative applicative) { this::testLazyZip) ) .peek(s -> IO.throwing(new AssertionError("The following Applicative laws did not hold for instance of " - + applicative.getClass() + ": \n\t - " + s))); + + equivalence + ": \n\t - " + s))); } - private Maybe testIdentity(Applicative applicative) { - Applicative v = applicative.pure(1); - Applicative, App> pureId = v.pure(id()); - return v.zip(pureId).equals(v) + private Maybe testIdentity(Equivalence> equivalence) { + return equivalence.invMap(app -> app.zip(app.pure(id()))).equals(equivalence) ? nothing() : just("identity (v.zip(pureId).equals(v))"); } - private Maybe testComposition(Applicative applicative) { + private Maybe testComposition(Equivalence> equivalence) { Random random = new Random(); Integer firstInt = random.nextInt(100); Integer secondInt = random.nextInt(100); - Fn1, - Fn1, - Fn1>> compose = x -> x::contraMap; - Applicative, App> u = applicative.pure(x -> x + firstInt); - Applicative, App> v = applicative.pure(x -> x + secondInt); - Applicative w = applicative.pure("result: "); - - return w.zip(v.zip(u.zip(u.pure(compose)))).equals(w.zip(v).zip(u)) + return equivalence.invMap(app -> app.pure("result: ") + .zip(app.>pure(x1 -> x1 + secondInt) + .zip(app.>pure(x1 -> x1 + firstInt) + .zip(app.pure(x1 -> x1::contraMap))))) + .equals(equivalence.invMap(app -> app.pure("result: ") + .zip(app.>pure(x -> x + secondInt)) + .zip(app.>pure(x -> x + firstInt)))) ? nothing() : just("composition (w.zip(v.zip(u.zip(pureCompose))).equals((w.zip(v)).zip(u)))"); } - private Maybe testHomomorphism(Applicative applicative) { + private Maybe testHomomorphism(Equivalence> equivalence) { Fn1 f = x -> x + 1; int x = 1; - Applicative pureX = applicative.pure(x); - Applicative, App> pureF = applicative.pure(f); - Applicative pureFx = applicative.pure(f.apply(x)); - return pureX.zip(pureF).equals(pureFx) + return equivalence.invMap(app -> app.pure(x).zip(app.pure(f))) + .equals(equivalence.invMap(app -> app.pure(f.apply(x)))) ? nothing() : just("homomorphism (pureX.zip(pureF).equals(pureFx))"); } - private Maybe testInterchange(Applicative applicative) { - Applicative, App> u = applicative.pure(x -> x + 1); - int y = 1; - - Applicative pureY = applicative.pure(y); - return pureY.zip(u).equals(u.zip(applicative.pure(f -> f.apply(y)))) + private Maybe testInterchange(Equivalence> equivalence) { + int y = 1; + return equivalence.invMap(app -> app.pure(y).zip(app.pure(x -> x + 1))) + .equals(equivalence.invMap(app -> app.>pure(x -> x + 1) + .zip(app.pure(f -> f.apply(y))))) ? nothing() : just("interchange (pureY.zip(u).equals(u.zip(applicative.pure(f -> f.apply(y)))))"); } - private Maybe testDiscardL(Applicative applicative) { - Applicative u = applicative.pure("u"); - Applicative v = applicative.pure("v"); - - return u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(id()))))) + private Maybe testDiscardL(Equivalence> equivalence) { + return equivalence.invMap(app -> app.pure("u").discardL(app.pure("v"))) + .equals(equivalence.invMap(app -> app.pure("v") + .zip(app.pure("u").zip(app.pure(constantly(id())))))) ? nothing() : just("discardL u.discardL(v).equals(v.zip(u.zip(applicative.pure(constantly(identity())))))"); } - private Maybe testDiscardR(Applicative applicative) { - Applicative u = applicative.pure("u"); - Applicative v = applicative.pure("v"); - - return u.discardR(v).equals(v.zip(u.zip(applicative.pure(constantly())))) + private Maybe testDiscardR(Equivalence> equivalence) { + return equivalence.invMap(app -> app.pure("u").discardR(app.pure("v"))) + .equals(equivalence.invMap(app -> app.pure("v").zip(app.pure("u").zip(app.pure(constantly()))))) ? nothing() : just("discardR u.discardR(v).equals(v.zip(u.zip(applicative.pure(constantly()))))"); } - private Maybe testLazyZip(Applicative applicative) { - return applicative.lazyZip(lazy(applicative.pure(id()))).value().equals(applicative.zip(applicative.pure(id()))) + private Maybe testLazyZip(Equivalence> equivalence) { + return equivalence.invMap(app -> app.lazyZip(lazy(app.pure(id()))).value()) + .equals(equivalence.invMap(app -> app.zip(app.pure(id())))) ? nothing() : just("lazyZip app.zip(lazy(app.pure(id()))).equals(app.zip(app.pure(id())))"); } diff --git a/src/test/java/testsupport/traits/BifunctorLaws.java b/src/test/java/testsupport/traits/BifunctorLaws.java index d682435e6..3f940f47b 100644 --- a/src/test/java/testsupport/traits/BifunctorLaws.java +++ b/src/test/java/testsupport/traits/BifunctorLaws.java @@ -5,42 +5,47 @@ import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; -import com.jnape.palatable.traitor.traits.Trait; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static java.util.Arrays.asList; -public class BifunctorLaws> implements Trait> { +public class BifunctorLaws> implements EquivalenceTrait> { @Override - public void test(Bifunctor bifunctor) { + public Class> type() { + return Bifunctor.class; + } + + @Override + public void test(Equivalence> equivalence) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap( - f -> f.apply(bifunctor), + .>, Maybe>>foldMap( + f -> f.apply(equivalence), asList(this::testLeftIdentity, this::testRightIdentity, this::testMutualIdentity) ) .peek(s -> IO.throwing(new AssertionError("The following Bifunctor laws did not hold for instance of " + - bifunctor.getClass() + ": \n\t - " + s))); + equivalence + ": \n\t - " + s))); } - private Maybe testLeftIdentity(Bifunctor bifunctor) { - return bifunctor.biMapL(id()).equals(bifunctor) + private Maybe testLeftIdentity(Equivalence> equivalence) { + return equivalence.invMap(bf -> bf.biMapL(id())).equals(equivalence) ? nothing() : just("left identity (bifunctor.biMapL(id()).equals(bifunctor))"); } - private Maybe testRightIdentity(Bifunctor bifunctor) { - return bifunctor.biMapR(id()).equals(bifunctor) + private Maybe testRightIdentity(Equivalence> equivalence) { + return equivalence.invMap(bf -> bf.biMapR(id())).equals(equivalence) ? nothing() : just("right identity (bifunctor.biMapR(id()).equals(bifunctor))"); } - private Maybe testMutualIdentity(Bifunctor bifunctor) { - return bifunctor.biMapL(id()).biMapR(id()).equals(bifunctor.biMap(id(), id())) + private Maybe testMutualIdentity(Equivalence> equivalence) { + return equivalence.invMap(bf -> bf.biMapL(id()).biMapR(id())) + .equals(equivalence.invMap(bf -> bf.biMap(id(), id()))) ? nothing() : just("mutual identity (bifunctor.biMapL(id()).biMapR(id()).equals(bifunctor.biMap(id(),id()))"); } diff --git a/src/test/java/testsupport/traits/Equivalence.java b/src/test/java/testsupport/traits/Equivalence.java new file mode 100644 index 000000000..7421256f3 --- /dev/null +++ b/src/test/java/testsupport/traits/Equivalence.java @@ -0,0 +1,53 @@ +package testsupport.traits; + +import com.jnape.palatable.lambda.functions.Fn1; + +import java.util.Objects; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; + +public final class Equivalence { + + private final A value; + private final Fn1 eq; + + private Equivalence(A value, Fn1 eq) { + this.value = value; + this.eq = eq; + } + + public A getValue() { + return value; + } + + public Equivalence swap(A a) { + return invMap(constantly(a)); + } + + public Equivalence invMap(Fn1 equivalence) { + return new Equivalence<>(value, equivalence.fmap(this.eq)); + } + + @Override + public String toString() { + return value.getClass().getSimpleName() + " (surrogate)"; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Equivalence) { + @SuppressWarnings("unchecked") Equivalence other = (Equivalence) obj; + return Objects.equals(eq.apply(value), other.eq.apply(other.value)); + } + return false; + } + + public static Equivalence equivalence(A value, Fn1 equivalence) { + return new Equivalence<>(value, equivalence); + } +} diff --git a/src/test/java/testsupport/traits/EquivalenceTrait.java b/src/test/java/testsupport/traits/EquivalenceTrait.java new file mode 100644 index 000000000..1c83ddb8e --- /dev/null +++ b/src/test/java/testsupport/traits/EquivalenceTrait.java @@ -0,0 +1,33 @@ +package testsupport.traits; + +import com.jnape.palatable.traitor.traits.Trait; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static testsupport.traits.Equivalence.equivalence; + +public interface EquivalenceTrait extends Trait { + + Class type(); + + void test(Equivalence equivalence); + + @Override + default void test(Object value) { + Class type = type(); + if (value instanceof Equivalence) { + if (type.isInstance(((Equivalence) value).getValue())) { + @SuppressWarnings("unchecked") Equivalence equivalenceC = (Equivalence) value; + test(equivalenceC); + return; + } else { + throw new ClassCastException("Unable to create " + type.getSimpleName() + + " surrogate for value of type " + value.getClass()); + } + } + if (!type.isInstance(value)) + throw new ClassCastException("Unable to create " + type.getSimpleName() + " surrogate for value of type " + + value.getClass().getSimpleName()); + @SuppressWarnings("unchecked") A b = (A) value; + test(equivalence(b, id())); + } +} diff --git a/src/test/java/testsupport/traits/FunctorLaws.java b/src/test/java/testsupport/traits/FunctorLaws.java index 5fc7d5937..4a477188f 100644 --- a/src/test/java/testsupport/traits/FunctorLaws.java +++ b/src/test/java/testsupport/traits/FunctorLaws.java @@ -5,7 +5,6 @@ import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; -import com.jnape.palatable.traitor.traits.Trait; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; @@ -13,30 +12,35 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static java.util.Arrays.asList; -public class FunctorLaws> implements Trait> { +public class FunctorLaws> implements EquivalenceTrait> { @Override - public void test(Functor f) { + public Class> type() { + return Functor.class; + } + + @Override + public void test(Equivalence> equivalence) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap( - fn -> fn.apply(f), + .>, Maybe>>foldMap( + fn -> fn.apply(equivalence), asList(this::testIdentity, this::testComposition)) .peek(s -> IO.throwing(new AssertionError("The following Functor laws did not hold for instance of " + - f.getClass() + ": \n\t - " + s))); + equivalence + ": \n\t - " + s))); } - private Maybe testIdentity(Functor f) { - return f.fmap(id()).equals(f) + private Maybe testIdentity(Equivalence> equivalence) { + return equivalence.invMap(f -> f.fmap(id())).equals(equivalence) ? nothing() : just("identity (f.fmap(identity()).equals(f))"); } - private Maybe testComposition(Functor functor) { - Functor subject = functor.fmap(constantly(1)); - Fn1 f = x -> x * 3; - Fn1 g = x -> x - 2; - return subject.fmap(f.contraMap(g)).equals(subject.fmap(g).fmap(f)) + private Maybe testComposition(Equivalence> equivalence) { + Fn1 g = x -> x * 3; + Fn1 h = x -> x - 2; + return equivalence.invMap(f -> f.fmap(constantly(1)).fmap(g).fmap(h)) + .equals(equivalence.invMap(f -> f.fmap(constantly(1)).fmap(g.fmap(h)))) ? nothing() : just("composition (functor.fmap(f.contraMap(g)).equals(functor.fmap(g).fmap(f)))"); } diff --git a/src/test/java/testsupport/traits/MonadLaws.java b/src/test/java/testsupport/traits/MonadLaws.java index 2ff5a6e77..6f1f08357 100644 --- a/src/test/java/testsupport/traits/MonadLaws.java +++ b/src/test/java/testsupport/traits/MonadLaws.java @@ -5,56 +5,59 @@ import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monoid.builtin.Present; -import com.jnape.palatable.traitor.traits.Trait; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; import static com.jnape.palatable.lambda.monad.Monad.join; import static java.util.Arrays.asList; -public class MonadLaws> implements Trait> { +public class MonadLaws> implements EquivalenceTrait> { @Override - public void test(Monad m) { + public Class> type() { + return Monad.class; + } + + @Override + public void test(Equivalence> equivalence) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap(f -> f.apply(m), asList( + .>, Maybe>>foldMap(f -> f.apply(equivalence), asList( this::testLeftIdentity, this::testRightIdentity, this::testAssociativity, this::testJoin)) .peek(s -> IO.throwing(new AssertionError("The following Monad laws did not hold for instance of " + - m.getClass() + ": \n\t - " + s))); + equivalence + ": \n\t - " + s))); } - private Maybe testLeftIdentity(Monad m) { - Object a = new Object(); - Fn1> fn = id().fmap(m::pure); - return m.pure(a).flatMap(fn).equals(fn.apply(a)) + private Maybe testLeftIdentity(Equivalence> equivalence) { + Object a = new Object(); + return equivalence.invMap(m -> m.pure(a.hashCode())) + .equals(equivalence.invMap(m -> m.pure(a.hashCode()))) ? nothing() : just("left identity (m.pure(a).flatMap(fn).equals(fn.apply(a)))"); } - private Maybe testRightIdentity(Monad m) { - return m.flatMap(m::pure).equals(m) + private Maybe testRightIdentity(Equivalence> equivalence) { + return equivalence.invMap(m -> m.flatMap(m::pure)).equals(equivalence) ? nothing() : just("right identity: (m.flatMap(m::pure).equals(m))"); } - private Maybe testAssociativity(Monad m) { - Fn1> f = constantly(m.pure(new Object())); - Fn1> g = constantly(m.pure(new Object())); - return m.flatMap(f).flatMap(g).equals(m.flatMap(a -> f.apply(a).flatMap(g))) + private Maybe testAssociativity(Equivalence> equivalence) { + Object a = new Object(); + Object b = new Object(); + return equivalence.invMap(m -> m.flatMap(constantly(m.pure(a))).flatMap(constantly(m.pure(b)))) + .equals(equivalence.invMap(m -> m.flatMap(__ -> m.pure(a).flatMap(constantly(m.pure(b)))))) ? nothing() : just("associativity: (m.flatMap(f).flatMap(g).equals(m.flatMap(a -> f.apply(a).flatMap(g))))"); } - private Maybe testJoin(Monad m) { - Monad, M> mma = m.pure(m.fmap(upcast())); - boolean equals = mma.flatMap(id()).equals(join(mma)); - return equals + private Maybe testJoin(Equivalence> equivalence) { + return equivalence.invMap(m -> m.pure(m).flatMap(id())) + .equals(equivalence.invMap(m -> join(m.pure(m)))) ? nothing() : just("join: (m.pure(m).flatMap(id())).equals(Monad.join(m.pure(m)))"); } diff --git a/src/test/java/testsupport/traits/MonadReaderLaws.java b/src/test/java/testsupport/traits/MonadReaderLaws.java new file mode 100644 index 000000000..900f73c98 --- /dev/null +++ b/src/test/java/testsupport/traits/MonadReaderLaws.java @@ -0,0 +1,37 @@ +package testsupport.traits; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monad.MonadReader; +import com.jnape.palatable.lambda.monoid.builtin.Present; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static java.util.Collections.singletonList; + +public class MonadReaderLaws> implements EquivalenceTrait> { + + @Override + public Class> type() { + return MonadReader.class; + } + + @Override + public void test(Equivalence> equivalence) { + Present.present((x, y) -> x + "\n\t - " + y) + .>, Maybe>>foldMap( + f -> f.apply(equivalence), + singletonList(this::testLocalIdentity) + ) + .peek(s -> IO.throwing(new AssertionError("The following MonadReader laws did not hold for instance of " + + equivalence + ": \n\t - " + s))); + } + + private Maybe testLocalIdentity(Equivalence> equivalence) { + return equivalence.invMap(mr -> mr.local(id())).equals(equivalence) + ? nothing() + : just("local identity (mr.local(id()).equals(mr))"); + } +} diff --git a/src/test/java/testsupport/traits/MonadWriterLaws.java b/src/test/java/testsupport/traits/MonadWriterLaws.java new file mode 100644 index 000000000..3cf4ea13c --- /dev/null +++ b/src/test/java/testsupport/traits/MonadWriterLaws.java @@ -0,0 +1,45 @@ +package testsupport.traits; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monad.MonadWriter; +import com.jnape.palatable.lambda.monoid.builtin.Present; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static java.util.Arrays.asList; + +public class MonadWriterLaws> implements EquivalenceTrait> { + + @Override + public Class> type() { + return MonadWriter.class; + } + + @Override + public void test(Equivalence> equivalence) { + Present.present((x, y) -> x + "\n\t - " + y) + .>, Maybe>>foldMap( + f -> f.apply(equivalence), asList( + this::testCensor, + this::testListens) + ) + .peek(s -> IO.throwing(new AssertionError("The following MonadWriter laws did not hold for instance" + + " of " + equivalence + ": \n\t - " + s))); + } + + private Maybe testCensor(Equivalence> equivalence) { + return equivalence.invMap(mw -> mw.censor(id())).equals(equivalence) + ? nothing() + : just("censor (mw.censor(id()).equals(mw))"); + } + + private Maybe testListens(Equivalence> equivalence) { + return equivalence.invMap(mw -> mw.listens(id()).fmap(Tuple2::_1)).equals(equivalence) + ? nothing() + : just("censor (mw.censor(id()).equals(mw))"); + } +} diff --git a/src/test/java/testsupport/traits/TraversableLaws.java b/src/test/java/testsupport/traits/TraversableLaws.java index c0a6c4968..9a11b8f2f 100644 --- a/src/test/java/testsupport/traits/TraversableLaws.java +++ b/src/test/java/testsupport/traits/TraversableLaws.java @@ -9,7 +9,6 @@ import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.lambda.traversable.Traversable; -import com.jnape.palatable.traitor.traits.Trait; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -17,52 +16,68 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static java.util.Arrays.asList; -@SuppressWarnings("Convert2MethodRef") -public class TraversableLaws> implements Trait> { +public class TraversableLaws> implements EquivalenceTrait> { @Override - public void test(Traversable traversable) { + public Class> type() { + return Traversable.class; + } + + @Override + public void test(Equivalence> equivalence) { Present.present((x, y) -> x + "\n\t - " + y) - ., Maybe>>foldMap( - f -> f.apply(traversable), + .>, Maybe>>foldMap( + f -> f.apply(equivalence), asList(this::testNaturality, this::testIdentity, this::testComposition) ) .peek(s -> IO.throwing(new AssertionError("The following Traversable laws did not hold for instance of " - + traversable.getClass() + ": \n\t - " + s))); + + equivalence + ": \n\t - " + s))); } - private Maybe testNaturality(Traversable trav) { + @SuppressWarnings("unchecked") + private Maybe testNaturality(Equivalence> equivalence) { Fn1> f = Identity::new; Fn1, Either> t = id -> right(id.runIdentity()); - Fn1, Applicative, Identity>> pureFn = - x -> new Identity<>(x); - Fn1, Applicative, Either>> pureFn2 = - x -> right(x); + Fn1, Identity>> pureFn = Identity::new; + Fn1, Either>> pureFn2 = Either::right; - return t.apply(trav.traverse(f, pureFn).fmap(id()).coerce()) - .equals(trav.traverse(t.contraMap(f), pureFn2).fmap(id()).coerce()) + Traversable trav = equivalence.getValue(); + return t.apply(trav.traverse(f, pureFn).fmap(id())).fmap(value -> equivalence.swap((Traversable) value)) + .equals(trav.traverse(t.contraMap(f), pureFn2) + .fmap(equivalence::swap)) ? nothing() : just("naturality (t.apply(trav.traverse(f, pureFn).fmap(id()).coerce())\n" + - " .equals(trav.traverse(t.contraMap(f), pureFn2).fmap(id()).coerce()))"); + " .equals(trav.traverse(t.contraMap(f), pureFn2)" + + ".fmap(id()).coerce()))"); } - private Maybe testIdentity(Traversable trav) { - return trav.traverse(Identity::new, x -> new Identity<>(x)).equals(new Identity<>(trav)) + private Maybe testIdentity(Equivalence> equivalence) { + Traversable trav = equivalence.getValue(); + return trav.traverse(Identity::new, Identity::new).fmap(equivalence::swap) + .equals(new Identity<>(trav).fmap(equivalence::swap)) ? nothing() : just("identity (trav.traverse(Identity::new, x -> new Identity<>(x)).equals(new Identity<>(trav))"); } - private Maybe testComposition(Traversable trav) { + private Maybe testComposition(Equivalence> equivalence) { Fn1> f = Identity::new; - Fn1>> g = x -> new Identity<>(x); + Fn1>> g = Identity::new; - return trav.traverse(f.fmap(x -> x.fmap(g)).fmap(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x)))) - .equals(new Compose<>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x))))) + Traversable trav = equivalence.getValue(); + return trav.traverse(f.fmap(x -> x.fmap(g)).fmap(Compose::new), + x -> new Compose<>(new Identity<>(new Identity<>(x)))) + .fmap(equivalence::swap) + .equals(new Compose<>(trav.traverse(f, Identity::new) + .fmap(t -> t.traverse(g, Identity::new))) + .fmap(equivalence::swap)) ? nothing() - : just("compose (trav.traverse(f.fmap(x -> x.fmap(g)).fmap(Compose::new), x -> new Compose<>(new Identity<>(new Identity<>(x))))\n" + - " .equals(new Compose>(trav.traverse(f, x -> new Identity<>(x)).fmap(t -> t.traverse(g, x -> new Identity<>(x))))))"); + : just("compose (trav.traverse(f.fmap(x -> x.fmap(g)).fmap(Compose::new), x -> new Compose<>(" + + "new Identity<>(new Identity<>(x))))\n" + + " .equals(new Compose>(" + + "trav.traverse(f, x -> new Identity<>(x))" + + ".fmap(t -> t.traverse(g, x -> new Identity<>(x))))))"); } } From 389a308b04725b5aa35ce610d6712e4eb6c4ae61 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 27 Aug 2019 17:34:44 -0500 Subject: [PATCH 230/348] fixing 1.8.0_162 inference --- .../java/com/jnape/palatable/lambda/functor/builtin/State.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java index 126be9e4e..8c1e84a41 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java @@ -172,8 +172,9 @@ public State discardL(Applicative> appB) { * @param the state and result type * @return the new {@link State} instance */ + @SuppressWarnings("RedundantTypeArguments") public static State get() { - return state(Tuple2::fill); + return state(Tuple2::fill); } /** From 2f0cd6b8ae76d427fe543e7ffb6ff9647452b990 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 1 Sep 2019 20:10:32 -0500 Subject: [PATCH 231/348] Better determinism across CPUs with varying thread scheduling algorithms --- .../java/com/jnape/palatable/lambda/io/IOTest.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index b6abb76de..fa3291408 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -349,18 +349,19 @@ public void monitorSync() throws InterruptedException { Object lock = new Object(); List accesses = new ArrayList<>(); CountDownLatch oneStarted = new CountDownLatch(1); + CountDownLatch twoStarted = new CountDownLatch(1); CountDownLatch finishLine = new CountDownLatch(2); IO one = IO.monitorSync(lock, io(() -> { accesses.add("one entered"); oneStarted.countDown(); - Thread.sleep(10); + twoStarted.await(); + Thread.sleep(100); accesses.add("one exited"); finishLine.countDown(); })); IO two = IO.monitorSync(lock, io(() -> { - oneStarted.await(); accesses.add("two entered"); accesses.add("two exited"); finishLine.countDown(); @@ -370,11 +371,16 @@ public void monitorSync() throws InterruptedException { start(); }}; - new Thread(two::unsafePerformIO) {{ + oneStarted.await(); + + new Thread(() -> { + twoStarted.countDown(); + two.unsafePerformIO(); + }) {{ start(); }}; - if (!finishLine.await(15, SECONDS)) + if (!finishLine.await(1, SECONDS)) fail("Expected threads to have completed by now, only got this far: " + accesses); assertEquals(asList("one entered", "one exited", "two entered", "two exited"), accesses); } From d5e2291d2315b0d41c9c8629ecc424eb68bd5a9f Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 6 Sep 2019 16:45:18 -0500 Subject: [PATCH 232/348] Deprecating peek --- CHANGELOG.md | 3 ++ .../jnape/palatable/lambda/adt/Either.java | 14 +++++--- .../com/jnape/palatable/lambda/adt/Maybe.java | 8 +++-- .../lambda/functions/builtin/fn2/Peek.java | 2 ++ .../lambda/functions/builtin/fn2/Peek2.java | 2 ++ .../palatable/lambda/adt/EitherTest.java | 33 ------------------- .../jnape/palatable/lambda/adt/MaybeTest.java | 12 ------- .../functions/builtin/fn2/Peek2Test.java | 33 ------------------- .../functions/builtin/fn2/PeekTest.java | 29 ---------------- .../testsupport/assertion/LensAssert.java | 3 +- .../assertion/MonadErrorAssert.java | 6 ++-- .../testsupport/assertion/PrismAssert.java | 3 +- .../testsupport/matchers/LeftMatcher.java | 11 ++++--- .../testsupport/matchers/RightMatcher.java | 11 ++++--- .../testsupport/traits/ApplicativeLaws.java | 10 +++--- .../testsupport/traits/BifunctorLaws.java | 7 ++-- .../java/testsupport/traits/FunctorLaws.java | 7 ++-- .../java/testsupport/traits/MonadLaws.java | 7 ++-- .../testsupport/traits/MonadReaderLaws.java | 7 ++-- .../testsupport/traits/MonadWriterLaws.java | 7 ++-- .../testsupport/traits/TraversableLaws.java | 7 ++-- 21 files changed, 78 insertions(+), 144 deletions(-) delete mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java delete mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f1fe6d8c6..faf73952a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `WriterT`, a monad transformer for an accumulation and a value - `EquivalenceTrait`, a traitor `Trait` to make it easier to test properties of type-classes with a separate equivalence relation + +### Deprecated +- `Peek`, `Peek2`, `Maybe#peek`, and `Either#peek` in favor of explicitly matching into `IO` and running it ## [4.0.0] - 2019-05-20 ### Changed 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 9c63c54a5..b7f3a6ce3 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -5,8 +5,6 @@ import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; -import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; -import com.jnape.palatable.lambda.functions.builtin.fn2.Peek2; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; @@ -19,9 +17,11 @@ import java.util.Objects; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.io.IO.io; import static java.util.Arrays.asList; /** @@ -166,9 +166,13 @@ public final Either merge(Fn2 leftFn, * * @param effect the effecting consumer * @return the Either, unaltered + * @deprecated in favor of {@link Either#match(Fn1, Fn1) matching} into an {@link IO} and explicitly running it */ + @Deprecated public Either peek(Fn1> effect) { - return Peek.peek(effect, this); + return match(l -> io(Either.left(l)), + r -> effect.apply(r).fmap(constantly(this))) + .unsafePerformIO(); } /** @@ -177,9 +181,11 @@ public Either peek(Fn1> effect) { * @param leftEffect the effecting consumer for left values * @param rightEffect the effecting consumer for right values * @return the Either, unaltered + * @deprecated in favor of {@link Either#match(Fn1, Fn1) matching} into an {@link IO} and explicitly running it */ + @Deprecated public Either peek(Fn1> leftEffect, Fn1> rightEffect) { - return Peek2.peek2(leftEffect, rightEffect, this); + return match(leftEffect, rightEffect).fmap(constantly(this)).unsafePerformIO(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index d2cb62ed8..cc5b18899 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -7,7 +7,6 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.builtin.fn2.Peek; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; @@ -26,6 +25,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.io.IO.io; /** * The optional type, representing a potentially absent value. This is lambda's analog of {@link Optional}, supporting @@ -223,9 +223,11 @@ public Choice2 invert() { * * @param effect the consumer * @return the same Maybe instance + * @deprecated in favor of {@link Maybe#match(Fn1, Fn1) matching} into an {@link IO} and explicitly running it */ + @Deprecated public final Maybe peek(Fn1> effect) { - return Peek.peek(effect, this); + return match(constantly(io(this)), a -> effect.apply(a).fmap(constantly(this))).unsafePerformIO(); } @Override @@ -302,7 +304,7 @@ public static Maybe nothing() { * * @return the {@link Pure} instance */ - public static Pure> pureMaybe() { + public static Pure> pureMaybe() { return Maybe::just; } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java index bea6bb1c5..c793b45b7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek.java @@ -12,7 +12,9 @@ * * @param the functor parameter type * @param the functor type + * @deprecated in favor of producing an {@link IO} from the given {@link Functor} and explicitly running it */ +@Deprecated public final class Peek> implements Fn2>, FA, FA> { private static final Peek INSTANCE = new Peek<>(); diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java index 3114f26c1..bcc98eb55 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2.java @@ -15,7 +15,9 @@ * @param the bifunctor's first parameter type * @param the bifunctor's second parameter type * @param the bifunctor type + * @deprecated in favor of producing an {@link IO} from the given {@link BoundedBifunctor} and explicitly running it */ +@Deprecated public final class Peek2> implements Fn3>, Fn1>, FAB, FAB> { private static final Peek2 INSTANCE = new Peek2<>(); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java index 958140086..40ec74e61 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java @@ -15,7 +15,6 @@ import testsupport.traits.TraversableLaws; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; import static com.jnape.palatable.lambda.adt.Either.fromMaybe; import static com.jnape.palatable.lambda.adt.Either.left; @@ -23,7 +22,6 @@ 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.Unit.UNIT; -import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.hamcrest.core.Is.is; @@ -201,37 +199,6 @@ public void monadTryingWithRunnable() { assertEquals(left(expected), Either.trying(() -> {throw expected;})); } - @Test - public void monadicPeekLiftsIOToTheRight() { - Either left = left("foo"); - Either right = right(1); - - AtomicInteger intRef = new AtomicInteger(); - - left.peek(fromConsumer(intRef::set)); - assertEquals(0, intRef.get()); - - right.peek(fromConsumer(intRef::set)); - assertEquals(1, intRef.get()); - } - - @Test - public void dyadicPeekDuallyLiftsIO() { - Either left = left("foo"); - Either right = right(1); - - AtomicReference stringRef = new AtomicReference<>(); - AtomicInteger intRef = new AtomicInteger(); - - left.peek(fromConsumer(stringRef::set), fromConsumer(intRef::set)); - assertEquals("foo", stringRef.get()); - assertEquals(0, intRef.get()); - - right.peek(fromConsumer(stringRef::set), fromConsumer(intRef::set)); - assertEquals("foo", stringRef.get()); - assertEquals(1, intRef.get()); - } - @Test public void lazyZip() { assertEquals(right(2), right(1).lazyZip(lazy(right(x -> x + 1))).value()); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java index 5d3d65763..636e9b784 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java @@ -13,7 +13,6 @@ import testsupport.traits.TraversableLaws; import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; @@ -25,7 +24,6 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Eq.eq; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; -import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; @@ -103,16 +101,6 @@ public void fromEither() { assertEquals(nothing(), Maybe.fromEither(left("failure"))); } - @Test - public void peek() { - AtomicInteger ref = new AtomicInteger(0); - assertEquals(just(1), just(1).peek(constantly(io(ref::incrementAndGet)))); - assertEquals(1, ref.get()); - - assertEquals(nothing(), nothing().peek(constantly(io(ref::incrementAndGet)))); - assertEquals(1, ref.get()); - } - @Test public void justOrThrow() { just(1).orElseThrow(IllegalStateException::new); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java deleted file mode 100644 index 3b0860b22..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/Peek2Test.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; - -import com.jnape.palatable.lambda.adt.Either; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import org.junit.Test; - -import java.util.concurrent.atomic.AtomicInteger; - -import static com.jnape.palatable.lambda.adt.Either.right; -import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek2.peek2; -import static org.junit.Assert.assertEquals; - -public class Peek2Test { - - @Test - public void peeksAtBothBifunctorValues() { - AtomicInteger counter = new AtomicInteger(0); - Tuple2 tuple = tuple(1, 2); - assertEquals(tuple, peek2(fromConsumer(__ -> counter.incrementAndGet()), - fromConsumer(__ -> counter.incrementAndGet()), tuple)); - assertEquals(2, counter.get()); - } - - @Test - public void followsSameConventionsAsBimap() { - AtomicInteger counter = new AtomicInteger(0); - Either either = right(1); - peek2(fromConsumer(__ -> counter.incrementAndGet()), fromConsumer(__ -> counter.incrementAndGet()), either); - assertEquals(1, counter.get()); - } -} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java deleted file mode 100644 index 5ab1fba4f..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PeekTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.jnape.palatable.lambda.functions.builtin.fn2; - -import com.jnape.palatable.lambda.adt.Maybe; -import org.junit.Test; - -import java.util.concurrent.atomic.AtomicInteger; - -import static com.jnape.palatable.lambda.adt.Maybe.just; -import static com.jnape.palatable.lambda.functions.Effect.fromConsumer; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek.peek; -import static org.junit.Assert.assertEquals; - -public class PeekTest { - - @Test - public void appliesConsumerToCarrierValue() { - AtomicInteger counter = new AtomicInteger(0); - Maybe maybeString = just("foo"); - assertEquals(maybeString, peek(fromConsumer(x -> counter.incrementAndGet()), maybeString)); - assertEquals(1, counter.get()); - } - - @Test - public void onlyAppliesIfFmapWould() { - AtomicInteger counter = new AtomicInteger(0); - Maybe.nothing().fmap(__ -> counter.incrementAndGet()); - assertEquals(0, counter.get()); - } -} \ No newline at end of file diff --git a/src/test/java/testsupport/assertion/LensAssert.java b/src/test/java/testsupport/assertion/LensAssert.java index 2c174cada..a64e80fd5 100644 --- a/src/test/java/testsupport/assertion/LensAssert.java +++ b/src/test/java/testsupport/assertion/LensAssert.java @@ -34,7 +34,8 @@ public static void assertLensLawfulness(Optic, Functor< .reduceLeft(asList(falsify("You get back what you put in", (s, b) -> view(lens, set(lens, b, s)), (s, b) -> b, cases), falsify("Putting back what you got changes nothing", (s, b) -> set(lens, view(lens, s), s), (s, b) -> s, cases), falsify("Setting twice is equivalent to setting once", (s, b) -> set(lens, b, set(lens, b, s)), (s, b) -> set(lens, b, s), cases))) - .peek(failures -> IO.throwing(new AssertionError("Lens law failures\n\n" + failures))); + .match(IO::io, failures -> IO.throwing(new AssertionError("Lens law failures\n\n" + failures))) + .unsafePerformIO(); } private static Maybe falsify(String label, Fn2 l, Fn2 r, diff --git a/src/test/java/testsupport/assertion/MonadErrorAssert.java b/src/test/java/testsupport/assertion/MonadErrorAssert.java index a4cc2e423..edcf2ba12 100644 --- a/src/test/java/testsupport/assertion/MonadErrorAssert.java +++ b/src/test/java/testsupport/assertion/MonadErrorAssert.java @@ -20,7 +20,8 @@ private MonadErrorAssert() { E e, Fn1 recovery) { subjects.forEach(subject -> throwCatch(equivalence(subject, id()), e, recovery) - .peek(failures -> IO.throwing(new AssertionError("MonadError law failures\n\n" + failures)))); + .match(IO::io, failures -> IO.throwing(new AssertionError("MonadError law failures\n\n" + failures))) + .unsafePerformIO()); } public static , MA extends MonadError> void assertLawsEq( @@ -28,7 +29,8 @@ private MonadErrorAssert() { E e, Fn1 recovery) { subjects.forEach(subject -> throwCatch(subject, e, recovery) - .peek(failures -> IO.throwing(new AssertionError("MonadError law failures\n\n" + failures)))); + .match(IO::io, failures -> IO.throwing(new AssertionError("MonadError law failures\n\n" + failures))) + .unsafePerformIO()); } private static , MA extends MonadError> Maybe throwCatch( diff --git a/src/test/java/testsupport/assertion/PrismAssert.java b/src/test/java/testsupport/assertion/PrismAssert.java index 9794678de..443130fb4 100644 --- a/src/test/java/testsupport/assertion/PrismAssert.java +++ b/src/test/java/testsupport/assertion/PrismAssert.java @@ -42,7 +42,8 @@ public static void assertPrismLawfulness(Prism prism, falsify("A non-match result can always be converted back to an input", (s, b) -> new PrismResult<>(matching(prism, s).projectA().fmap(matching(prism))), (s, b) -> new PrismResult<>(just(left(s))), cases))) - .peek(failures -> IO.throwing(new AssertionError("Lens law failures\n\n" + failures))); + .match(IO::io, failures -> IO.throwing(new AssertionError("Lens law failures\n\n" + failures))) + .unsafePerformIO(); } private static Maybe falsify(String label, Fn2 l, Fn2 r, diff --git a/src/test/java/testsupport/matchers/LeftMatcher.java b/src/test/java/testsupport/matchers/LeftMatcher.java index fa57261fe..34ea33079 100644 --- a/src/test/java/testsupport/matchers/LeftMatcher.java +++ b/src/test/java/testsupport/matchers/LeftMatcher.java @@ -30,11 +30,12 @@ public void describeTo(Description description) { @Override protected void describeMismatchSafely(Either item, Description mismatchDescription) { mismatchDescription.appendText("was "); - item.peek(l -> io(() -> { - mismatchDescription.appendText("Left value of "); - lMatcher.describeMismatch(l, mismatchDescription); - }), - r -> io(() -> mismatchDescription.appendValue(item))); + item.match(l -> io(() -> { + mismatchDescription.appendText("Left value of "); + lMatcher.describeMismatch(l, mismatchDescription); + }), + r -> io(() -> mismatchDescription.appendValue(item))) + .unsafePerformIO(); } public static LeftMatcher isLeftThat(Matcher lMatcher) { diff --git a/src/test/java/testsupport/matchers/RightMatcher.java b/src/test/java/testsupport/matchers/RightMatcher.java index cce44fe03..1eafc0ab1 100644 --- a/src/test/java/testsupport/matchers/RightMatcher.java +++ b/src/test/java/testsupport/matchers/RightMatcher.java @@ -30,11 +30,12 @@ public void describeTo(Description description) { @Override protected void describeMismatchSafely(Either item, Description mismatchDescription) { mismatchDescription.appendText("was "); - item.peek(l -> io(() -> mismatchDescription.appendValue(item)), - r -> io(() -> { - mismatchDescription.appendText("Right value of "); - rMatcher.describeMismatch(r, mismatchDescription); - })); + item.match(l -> io(() -> mismatchDescription.appendValue(item)), + r -> io(() -> { + mismatchDescription.appendText("Right value of "); + rMatcher.describeMismatch(r, mismatchDescription); + })) + .unsafePerformIO(); } public static RightMatcher isRightThat(Matcher rMatcher) { diff --git a/src/test/java/testsupport/traits/ApplicativeLaws.java b/src/test/java/testsupport/traits/ApplicativeLaws.java index 05278e84d..a193889fd 100644 --- a/src/test/java/testsupport/traits/ApplicativeLaws.java +++ b/src/test/java/testsupport/traits/ApplicativeLaws.java @@ -13,6 +13,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.io.IO.throwing; import static java.util.Arrays.asList; public class ApplicativeLaws> implements EquivalenceTrait> { @@ -33,10 +34,11 @@ public void test(Equivalence> equivalence) { this::testInterchange, this::testDiscardL, this::testDiscardR, - this::testLazyZip) - ) - .peek(s -> IO.throwing(new AssertionError("The following Applicative laws did not hold for instance of " - + equivalence + ": \n\t - " + s))); + this::testLazyZip)) + .match(IO::io, + s -> throwing(new AssertionError("The following Applicative laws did not hold for instance of " + + equivalence + ": \n\t - " + s))) + .unsafePerformIO(); } private Maybe testIdentity(Equivalence> equivalence) { diff --git a/src/test/java/testsupport/traits/BifunctorLaws.java b/src/test/java/testsupport/traits/BifunctorLaws.java index 3f940f47b..ba5f88d7e 100644 --- a/src/test/java/testsupport/traits/BifunctorLaws.java +++ b/src/test/java/testsupport/traits/BifunctorLaws.java @@ -9,6 +9,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.io.IO.throwing; import static java.util.Arrays.asList; public class BifunctorLaws> implements EquivalenceTrait> { @@ -27,8 +28,10 @@ public void test(Equivalence> equivalence) { this::testRightIdentity, this::testMutualIdentity) ) - .peek(s -> IO.throwing(new AssertionError("The following Bifunctor laws did not hold for instance of " + - equivalence + ": \n\t - " + s))); + .match(IO::io, + s -> throwing(new AssertionError("The following Bifunctor laws did not hold for instance of " + + equivalence + ": \n\t - " + s))) + .unsafePerformIO(); } private Maybe testLeftIdentity(Equivalence> equivalence) { diff --git a/src/test/java/testsupport/traits/FunctorLaws.java b/src/test/java/testsupport/traits/FunctorLaws.java index 4a477188f..0371b1c81 100644 --- a/src/test/java/testsupport/traits/FunctorLaws.java +++ b/src/test/java/testsupport/traits/FunctorLaws.java @@ -10,6 +10,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.io.IO.throwing; import static java.util.Arrays.asList; public class FunctorLaws> implements EquivalenceTrait> { @@ -26,8 +27,10 @@ public void test(Equivalence> equivalence) { fn -> fn.apply(equivalence), asList(this::testIdentity, this::testComposition)) - .peek(s -> IO.throwing(new AssertionError("The following Functor laws did not hold for instance of " + - equivalence + ": \n\t - " + s))); + .match(IO::io, + s -> throwing(new AssertionError("The following Functor laws did not hold for instance of " + + equivalence + ": \n\t - " + s))) + .unsafePerformIO(); } private Maybe testIdentity(Equivalence> equivalence) { diff --git a/src/test/java/testsupport/traits/MonadLaws.java b/src/test/java/testsupport/traits/MonadLaws.java index 6f1f08357..eda3b45c2 100644 --- a/src/test/java/testsupport/traits/MonadLaws.java +++ b/src/test/java/testsupport/traits/MonadLaws.java @@ -10,6 +10,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.io.IO.throwing; import static com.jnape.palatable.lambda.monad.Monad.join; import static java.util.Arrays.asList; @@ -28,8 +29,10 @@ public void test(Equivalence> equivalence) { this::testRightIdentity, this::testAssociativity, this::testJoin)) - .peek(s -> IO.throwing(new AssertionError("The following Monad laws did not hold for instance of " + - equivalence + ": \n\t - " + s))); + .match(IO::io, + s -> throwing(new AssertionError("The following Monad laws did not hold for instance of " + + equivalence + ": \n\t - " + s))) + .unsafePerformIO(); } private Maybe testLeftIdentity(Equivalence> equivalence) { diff --git a/src/test/java/testsupport/traits/MonadReaderLaws.java b/src/test/java/testsupport/traits/MonadReaderLaws.java index 900f73c98..2553500ae 100644 --- a/src/test/java/testsupport/traits/MonadReaderLaws.java +++ b/src/test/java/testsupport/traits/MonadReaderLaws.java @@ -9,6 +9,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.io.IO.throwing; import static java.util.Collections.singletonList; public class MonadReaderLaws> implements EquivalenceTrait> { @@ -25,8 +26,10 @@ public void test(Equivalence> equivalence) { f -> f.apply(equivalence), singletonList(this::testLocalIdentity) ) - .peek(s -> IO.throwing(new AssertionError("The following MonadReader laws did not hold for instance of " - + equivalence + ": \n\t - " + s))); + .match(IO::io, + s -> throwing(new AssertionError("The following MonadReader laws did not hold for instance of " + + equivalence + ": \n\t - " + s))) + .unsafePerformIO(); } private Maybe testLocalIdentity(Equivalence> equivalence) { diff --git a/src/test/java/testsupport/traits/MonadWriterLaws.java b/src/test/java/testsupport/traits/MonadWriterLaws.java index 3cf4ea13c..8024535b8 100644 --- a/src/test/java/testsupport/traits/MonadWriterLaws.java +++ b/src/test/java/testsupport/traits/MonadWriterLaws.java @@ -10,6 +10,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.io.IO.throwing; import static java.util.Arrays.asList; public class MonadWriterLaws> implements EquivalenceTrait> { @@ -27,8 +28,10 @@ public void test(Equivalence> equivalence) { this::testCensor, this::testListens) ) - .peek(s -> IO.throwing(new AssertionError("The following MonadWriter laws did not hold for instance" + - " of " + equivalence + ": \n\t - " + s))); + .match(IO::io, + s -> throwing(new AssertionError("The following MonadWriter laws did not hold for instance" + + " of " + equivalence + ": \n\t - " + s))) + .unsafePerformIO(); } private Maybe testCensor(Equivalence> equivalence) { diff --git a/src/test/java/testsupport/traits/TraversableLaws.java b/src/test/java/testsupport/traits/TraversableLaws.java index 9a11b8f2f..3b85202ba 100644 --- a/src/test/java/testsupport/traits/TraversableLaws.java +++ b/src/test/java/testsupport/traits/TraversableLaws.java @@ -14,6 +14,7 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.io.IO.throwing; import static java.util.Arrays.asList; public class TraversableLaws> implements EquivalenceTrait> { @@ -32,8 +33,10 @@ public void test(Equivalence> equivalence) { this::testIdentity, this::testComposition) ) - .peek(s -> IO.throwing(new AssertionError("The following Traversable laws did not hold for instance of " - + equivalence + ": \n\t - " + s))); + .match(IO::io, + s -> throwing(new AssertionError("The following Traversable laws did not hold for instance of " + + equivalence + ": \n\t - " + s))) + .unsafePerformIO(); } @SuppressWarnings("unchecked") From 62495daf7ad0ae5fe4cf0fba8286518109b0458e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 8 Sep 2019 15:48:33 -0500 Subject: [PATCH 233/348] Adding HMap#isEmpty --- .../jnape/palatable/lambda/adt/hmap/HMap.java | 9 ++++ .../palatable/lambda/adt/hmap/HMapTest.java | 47 +++++++++++-------- 2 files changed, 37 insertions(+), 19 deletions(-) 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 1a1907391..bf3362d77 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 @@ -115,6 +115,15 @@ public HMap removeAll(HMap hMap) { return alter(t -> t.keySet().removeAll(hMap.table.keySet())); } + /** + * Test whether this {@link HMap} is empty. + * + * @return true if the {@link HMap} is empty; false otherwise. + */ + public boolean isEmpty() { + return table.isEmpty(); + } + /** * Retrieve all the mapped keys. *

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 f9e849f78..5064c8048 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 @@ -39,11 +39,19 @@ public void getForAbsentKey() { .get(typeSafeKey())); } + @Test + public void isEmpty() { + assertTrue(emptyHMap().isEmpty()); + assertFalse(singletonHMap(typeSafeKey(), "foo").isEmpty()); + } + @Test public void storesTypeSafeKeyBaseValue() { TypeSafeKey.Simple stringKey = typeSafeKey(); - TypeSafeKey longKey = stringKey.andThen(simpleIso(Long::parseLong, String::valueOf)); - TypeSafeKey bigIntegerKey = longKey.andThen(simpleIso(BigInteger::valueOf, BigInteger::longValue)); + TypeSafeKey longKey = stringKey.andThen(simpleIso(Long::parseLong, + String::valueOf)); + TypeSafeKey bigIntegerKey = longKey.andThen(simpleIso(BigInteger::valueOf, + BigInteger::longValue)); HMap hMap = singletonHMap(stringKey, "1"); assertEquals(just("1"), hMap.get(stringKey)); @@ -54,7 +62,8 @@ public void storesTypeSafeKeyBaseValue() { assertEquals(emptyHMap().put(longKey, 1L).get(longKey), emptyHMap().put(stringKey, "1").get(longKey)); assertEquals(emptyHMap().put(stringKey, "1").get(stringKey), emptyHMap().put(longKey, 1L).get(stringKey)); - assertEquals(emptyHMap().put(stringKey, "1").get(stringKey), emptyHMap().put(bigIntegerKey, ONE).get(stringKey)); + assertEquals(emptyHMap().put(stringKey, "1").get(stringKey), + emptyHMap().put(bigIntegerKey, ONE).get(stringKey)); assertEquals(singletonHMap(stringKey, "1"), singletonHMap(longKey, 1L)); assertEquals(singletonHMap(stringKey, "1"), singletonHMap(bigIntegerKey, ONE)); @@ -82,9 +91,9 @@ public void put() { @Test public void putAll() { - TypeSafeKey stringKey1 = typeSafeKey(); - TypeSafeKey stringKey2 = typeSafeKey(); - TypeSafeKey intKey = typeSafeKey(); + TypeSafeKey stringKey1 = typeSafeKey(); + TypeSafeKey stringKey2 = typeSafeKey(); + TypeSafeKey intKey = typeSafeKey(); HMap left = hMap(stringKey1, "string value", intKey, 1); @@ -132,9 +141,9 @@ public void removeAll() { @Test public void containsKey() { - TypeSafeKey stringKey1 = typeSafeKey(); - TypeSafeKey stringKey2 = typeSafeKey(); - TypeSafeKey intKey = typeSafeKey(); + TypeSafeKey stringKey1 = typeSafeKey(); + TypeSafeKey stringKey2 = typeSafeKey(); + TypeSafeKey intKey = typeSafeKey(); HMap hMap = singletonHMap(stringKey1, "string"); @@ -158,8 +167,8 @@ public void demandForAbsentKey() { @Test @SuppressWarnings("serial") public void toMap() { - TypeSafeKey stringKey = typeSafeKey(); - TypeSafeKey intKey = typeSafeKey(); + TypeSafeKey stringKey = typeSafeKey(); + TypeSafeKey intKey = typeSafeKey(); assertEquals(new HashMap, Object>() {{ put(stringKey, "string"); @@ -192,14 +201,14 @@ public void values() { @Test public void convenienceStaticFactoryMethods() { - 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(); + 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); From 26d00841372185086a39842d2b7b7c31ba5cf998 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 8 Sep 2019 15:50:45 -0500 Subject: [PATCH 234/348] Reformatting, adding javadoc --- .../jnape/palatable/lambda/adt/Either.java | 1 + .../palatable/lambda/adt/hmap/Schema.java | 123 +++++++++++++++++- .../lambda/adt/hmap/TypeSafeKey.java | 17 ++- .../jnape/palatable/lambda/functions/Fn1.java | 1 + .../lambda/functor/builtin/Compose.java | 4 + .../jnape/palatable/lambda/optics/Lens.java | 4 + .../jnape/palatable/lambda/optics/Prism.java | 3 + .../palatable/lambda/adt/hmap/SchemaTest.java | 16 +-- .../lambda/adt/hmap/TypeSafeKeyTest.java | 12 +- .../functions/builtin/fn1/DowncastTest.java | 6 +- .../functions/builtin/fn1/ReverseTest.java | 2 +- .../functions/builtin/fn1/UnconsTest.java | 2 +- .../functions/builtin/fn1/UpcastTest.java | 6 +- .../builtin/fn2/CartesianProductTest.java | 5 +- .../functions/builtin/fn2/InGroupsOfTest.java | 9 +- .../functions/builtin/fn2/PartitionTest.java | 6 +- .../functions/builtin/fn2/SlideTest.java | 4 +- .../functions/builtin/fn2/TakeWhileTest.java | 2 +- .../lambda/functions/builtin/fn2/ZipTest.java | 3 +- .../functions/builtin/fn4/IfThenElseTest.java | 6 +- .../iteration/MappingIteratorTest.java | 4 +- .../PredicatedTakingIteratorTest.java | 12 +- .../iteration/TakingIteratorTest.java | 6 +- .../monad/transformer/builtin/LazyTTest.java | 1 - .../palatable/lambda/monoid/MonoidTest.java | 6 +- .../lambda/monoid/builtin/AndTest.java | 2 +- .../lambda/monoid/builtin/CollapseTest.java | 5 +- .../lambda/monoid/builtin/FirstTest.java | 2 +- .../lambda/monoid/builtin/LeftAnyTest.java | 2 +- .../lambda/monoid/builtin/MergeMapsTest.java | 7 +- .../lambda/monoid/builtin/OrTest.java | 2 +- .../lambda/monoid/builtin/PresentTest.java | 4 +- .../lambda/monoid/builtin/PutAllTest.java | 4 +- .../lambda/monoid/builtin/RightAnyTest.java | 2 +- .../lambda/semigroup/builtin/AbsentTest.java | 4 +- .../semigroup/builtin/CollapseTest.java | 5 +- .../lambda/semigroup/builtin/LeftAnyTest.java | 2 +- .../lambda/semigroup/builtin/MergeTest.java | 5 +- .../semigroup/builtin/RightAnyTest.java | 2 +- 39 files changed, 224 insertions(+), 85 deletions(-) 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 b7f3a6ce3..9437f8be9 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -414,6 +414,7 @@ public static Either right(R r) { /** * The canonical {@link Pure} instance for {@link Either}. * + * @param the left type * @return the {@link Pure} instance */ public static Pure> pureEither() { 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 index 4eee1b0fd..61c9b181a 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/Schema.java @@ -28,8 +28,16 @@ * @param the {@link HList} of values to focus on * @see TypeSafeKey */ -public interface Schema> extends Lens.Simple> { +public interface Schema extends Lens.Simple> { + /** + * Add a new {@link TypeSafeKey} to the head of this {@link Schema}. + * + * @param key the new head key + * @param the value the head key focuses on + * @param the new {@link HCons} of values + * @return the updated {@link Schema} + */ @SuppressWarnings({"unchecked", "RedundantTypeArguments"}) default > Schema add(TypeSafeKey key) { Lens, Maybe> lens = Lens.both(this, valueAt(key)) @@ -50,6 +58,13 @@ default > Schema add(TypeSafeKe }; } + /** + * Create a {@link Schema} from a single {@link TypeSafeKey}. + * + * @param key the {@link TypeSafeKey} + * @param the type of value the key focuses on + * @return the {@link Schema} + */ static Schema> schema(TypeSafeKey key) { Lens>, Maybe>> lens = valueAt(key) .mapA(ma -> ma.fmap(HList::singletonHList)) @@ -67,17 +82,50 @@ static Schema> schema(TypeSafeKey key) { }; } + /** + * Create a {@link Schema} from two {@link TypeSafeKey TypeSafeKeys}. + * + * @param aKey the first {@link TypeSafeKey} + * @param bKey the second {@link TypeSafeKey} + * @param the type of value the first key focuses on + * @param the type of value the second key focuses on + * @return the {@link Schema} + */ static Schema> schema(TypeSafeKey aKey, TypeSafeKey bKey) { return schema(bKey).add(aKey); } + /** + * Create a {@link Schema} from three {@link TypeSafeKey TypeSafeKeys}. + * + * @param aKey the first {@link TypeSafeKey} + * @param bKey the second {@link TypeSafeKey} + * @param cKey the third {@link TypeSafeKey} + * @param the type of value the first key focuses on + * @param the type of value the second key focuses on + * @param the type of value the third key focuses on + * @return the {@link Schema} + */ static Schema> schema(TypeSafeKey aKey, TypeSafeKey bKey, TypeSafeKey cKey) { return schema(bKey, cKey).add(aKey); } + /** + * Create a {@link Schema} from four {@link TypeSafeKey TypeSafeKeys}. + * + * @param aKey the first {@link TypeSafeKey} + * @param bKey the second {@link TypeSafeKey} + * @param cKey the third {@link TypeSafeKey} + * @param dKey the fourth {@link TypeSafeKey} + * @param the type of value the first key focuses on + * @param the type of value the second key focuses on + * @param the type of value the third key focuses on + * @param the type of value the fourth key focuses on + * @return the {@link Schema} + */ static Schema> schema(TypeSafeKey aKey, TypeSafeKey bKey, TypeSafeKey cKey, @@ -85,7 +133,21 @@ static Schema> schema(TypeSafeKey aKey, return schema(bKey, cKey, dKey).add(aKey); } - + /** + * Create a {@link Schema} from five {@link TypeSafeKey TypeSafeKeys}. + * + * @param aKey the first {@link TypeSafeKey} + * @param bKey the second {@link TypeSafeKey} + * @param cKey the third {@link TypeSafeKey} + * @param dKey the fourth {@link TypeSafeKey} + * @param eKey the fifth {@link TypeSafeKey} + * @param the type of value the first key focuses on + * @param the type of value the second key focuses on + * @param the type of value the third key focuses on + * @param the type of value the fourth key focuses on + * @param the type of value the fifth key focuses on + * @return the {@link Schema} + */ static Schema> schema(TypeSafeKey aKey, TypeSafeKey bKey, TypeSafeKey cKey, @@ -94,6 +156,23 @@ static Schema> schema(TypeSafeKey aK return schema(bKey, cKey, dKey, eKey).add(aKey); } + /** + * Create a {@link Schema} from six {@link TypeSafeKey TypeSafeKeys}. + * + * @param aKey the first {@link TypeSafeKey} + * @param bKey the second {@link TypeSafeKey} + * @param cKey the third {@link TypeSafeKey} + * @param dKey the fourth {@link TypeSafeKey} + * @param eKey the fifth {@link TypeSafeKey} + * @param fKey the sixth {@link TypeSafeKey} + * @param the type of value the first key focuses on + * @param the type of value the second key focuses on + * @param the type of value the third key focuses on + * @param the type of value the fourth key focuses on + * @param the type of value the fifth key focuses on + * @param the type of value the sixth key focuses on + * @return the {@link Schema} + */ static Schema> schema(TypeSafeKey aKey, TypeSafeKey bKey, TypeSafeKey cKey, @@ -103,6 +182,25 @@ static Schema> schema(TypeSafeKey the type of value the first key focuses on + * @param the type of value the second key focuses on + * @param the type of value the third key focuses on + * @param the type of value the fourth key focuses on + * @param the type of value the fifth key focuses on + * @param the type of value the sixth key focuses on + * @param the type of value the seventh key focuses on + * @return the {@link Schema} + */ static Schema> schema(TypeSafeKey aKey, TypeSafeKey bKey, TypeSafeKey cKey, @@ -113,6 +211,27 @@ static Schema> schema(TypeSafe return schema(bKey, cKey, dKey, eKey, fKey, gKey).add(aKey); } + /** + * Create a {@link Schema} from eight {@link TypeSafeKey TypeSafeKeys}. + * + * @param aKey the first {@link TypeSafeKey} + * @param bKey the second {@link TypeSafeKey} + * @param cKey the third {@link TypeSafeKey} + * @param dKey the fourth {@link TypeSafeKey} + * @param eKey the fifth {@link TypeSafeKey} + * @param fKey the sixth {@link TypeSafeKey} + * @param gKey the seventh {@link TypeSafeKey} + * @param hKey the eighth {@link TypeSafeKey} + * @param the type of value the first key focuses on + * @param the type of value the second key focuses on + * @param the type of value the third key focuses on + * @param the type of value the fourth key focuses on + * @param the type of value the fifth key focuses on + * @param the type of value the sixth key focuses on + * @param the type of value the seventh key focuses on + * @param the type of value the eighth key focuses on + * @return the {@link Schema} + */ static Schema> schema(TypeSafeKey aKey, TypeSafeKey bKey, TypeSafeKey cKey, diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java index 6a23e647c..d023f37d8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKey.java @@ -23,14 +23,17 @@ */ public interface TypeSafeKey extends Iso.Simple { - @Override default TypeSafeKey discardR(Applicative> appB) { Iso.Simple discarded = Iso.Simple.super.discardR(appB); return new TypeSafeKey() { @Override - public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { + public >, + CoF extends Functor>, + FB extends Functor, + FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { return discarded.apply(pafb); } @@ -65,8 +68,12 @@ default TypeSafeKey andThen(Iso.Simple f) { Iso.Simple composed = Iso.Simple.super.andThen(f); return new TypeSafeKey() { @Override - public >, CoF extends Functor>, FB extends Functor, FT extends Functor, PAFB extends Profunctor, PSFT extends Profunctor> PSFT apply( - PAFB pafb) { + public >, + CoF extends Functor>, + FB extends Functor, + FT extends Functor, + PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { return composed.apply(pafb); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index c44a991ea..74b82d187 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -317,6 +317,7 @@ static Fn1 fromFunction(Function function) /** * The canonical {@link Pure} instance for {@link Fn1}. * + * @param the input type * @return the {@link Pure} instance */ static Pure> pureFn1() { diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index 94f78d9cf..b0f0dff76 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -107,6 +107,10 @@ public String toString() { /** * The canonical {@link Pure} instance for {@link Compose}. * + * @param pureF the {@link Pure} constructor for the outer {@link Applicative} + * @param pureG the {@link Pure} constructor for the inner {@link Applicative} + * @param the outer {@link Applicative} type + * @param the inner {@link Applicative} type * @return the {@link Pure} instance */ public static , G extends Applicative> Pure> pureCompose( diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java index 0d3297c2d..120be9964 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java @@ -381,6 +381,10 @@ static Lens.Simple> both(Lens.Simple f, Lens.Sim /** * The canonical {@link Pure} instance for {@link Lens}. * + * @param sa the getting function + * @param the type of the "larger" value for reading + * @param the type of the "smaller" value that is read + * @param the type of the "smaller" update value * @return the {@link Pure} instance */ static Pure> pureLens(Fn1 sa) { diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java index 16b81f23d..3bf6b72b4 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -333,6 +333,9 @@ static Prism fromPartial(Fn1 parti /** * The canonical {@link Pure} instance for {@link Prism}. * + * @param the input that might fail to map to its output + * @param the output that might fail to be produced + * @param the input that guarantees its output * @return the {@link Pure} instance */ static Pure> purePrism() { 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 index 3fdbde74f..d5cf6500c 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/SchemaTest.java @@ -18,14 +18,14 @@ 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(); + 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, diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java index f03acea5b..cf9f68cf8 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hmap/TypeSafeKeyTest.java @@ -24,9 +24,9 @@ public void lensLawfulness() { @Test public void compositionMapsOriginalValueInAndOutOfHMap() { - TypeSafeKey.Simple stringKey = typeSafeKey(); - TypeSafeKey intKey = stringKey.andThen(simpleIso(Integer::parseInt, Object::toString)); - HMap map = emptyHMap().put(stringKey, "123"); + TypeSafeKey.Simple stringKey = typeSafeKey(); + TypeSafeKey intKey = stringKey.andThen(simpleIso(Integer::parseInt, Object::toString)); + HMap map = emptyHMap().put(stringKey, "123"); assertEquals(just("123"), map.get(stringKey)); assertEquals(just(123), map.get(intKey)); @@ -40,16 +40,16 @@ public void compositionMapsOriginalValueInAndOutOfHMap() { @Test public void discardRPreservesTypeSafeKey() { - TypeSafeKey.Simple stringKey = typeSafeKey(); + TypeSafeKey.Simple stringKey = typeSafeKey(); TypeSafeKey discardedKey = stringKey.discardR(simpleIso(id(), id())); - HMap map = emptyHMap().put(stringKey, "123"); + HMap map = emptyHMap().put(stringKey, "123"); assertEquals(just("123"), map.get(discardedKey)); } @Test public void defaultEquality() { - TypeSafeKey.Simple keyA = typeSafeKey(); + TypeSafeKey.Simple keyA = typeSafeKey(); TypeSafeKey mappedKeyA = keyA.andThen(simpleIso(id(), id())); assertEquals(keyA, keyA); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java index b21e30b73..585419e1b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DowncastTest.java @@ -13,16 +13,16 @@ public class DowncastTest { @SuppressWarnings("unused") public void safeDowncast() { CharSequence charSequence = "123"; - String s = downcast(charSequence); + String s = downcast(charSequence); Functor> maybeInt = nothing(); - Maybe cast = downcast(maybeInt); + Maybe cast = downcast(maybeInt); } @Test(expected = ClassCastException.class) @SuppressWarnings({"JavacQuirks", "unused"}) public void unsafeDowncast() { CharSequence charSequence = "123"; - Integer explosion = downcast(charSequence); + Integer explosion = downcast(charSequence); } } \ 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 434ed4ba2..39a133bcb 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 @@ -30,7 +30,7 @@ public Reverse createTestSubject() { @Test public void iteratesElementsOfAnIterableBackwards() { - Iterable words = asList("the", "rain", "in", "Spain"); + Iterable words = asList("the", "rain", "in", "Spain"); Iterable reversed = reverse(words); assertThat(reversed, iterates("Spain", "in", "rain", "the")); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java index 115ba8164..01abfdcd2 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java @@ -25,7 +25,7 @@ public Uncons testSubject() { @Test public void nonEmptyIterable() { - Iterable numbers = asList(1, 2, 3); + Iterable numbers = asList(1, 2, 3); Tuple2> headAndTail = uncons(numbers).orElseThrow(AssertionError::new); assertEquals((Integer) 1, headAndTail._1()); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UpcastTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UpcastTest.java index a93d83537..2a5fa7e55 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UpcastTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UpcastTest.java @@ -11,8 +11,8 @@ public class UpcastTest { @Test @SuppressWarnings("unused") public void castsUp() { - Upcast upcast = upcast(); - Iterable strings = asList("foo", "bar"); - Iterable charSequences = map(upcast, strings); + Upcast upcast = upcast(); + Iterable strings = asList("foo", "bar"); + Iterable charSequences = map(upcast, strings); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProductTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProductTest.java index b6b74e9e4..07780e82b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProductTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/CartesianProductTest.java @@ -18,7 +18,6 @@ import static testsupport.matchers.IterableMatcher.iterates; @RunWith(Traits.class) -@SuppressWarnings("unchecked") public class CartesianProductTest { @TestTraits({Laziness.class, ImmutableIteration.class, EmptyIterableSupport.class, FiniteIteration.class}) @@ -29,7 +28,7 @@ public Fn1, Iterable>> createTestSubjec @Test public void computesCartesianProductOfTwoEquallySizedIterables() { Iterable numbers = asList(1, 2, 3); - Iterable letters = asList("a", "b", "c"); + Iterable letters = asList("a", "b", "c"); assertThat( cartesianProduct(numbers, letters), @@ -50,7 +49,7 @@ public void computesCartesianProductOfTwoEquallySizedIterables() { @Test public void worksForTwoUnequallySizedIterables() { Iterable oneThroughThree = asList(1, 2, 3); - Iterable aAndB = asList("a", "b"); + Iterable aAndB = asList("a", "b"); assertThat( cartesianProduct(oneThroughThree, aAndB), diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOfTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOfTest.java index c341257a9..587ee7d88 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOfTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/InGroupsOfTest.java @@ -16,7 +16,6 @@ import static org.junit.Assert.assertThat; import static testsupport.matchers.IterableMatcher.iterates; -@SuppressWarnings("unchecked") @RunWith(Traits.class) public class InGroupsOfTest { @@ -27,15 +26,15 @@ public Fn1, Iterable>> createTestSubject() { @Test public void evenlyDistributesGroupedElementsOverIterable() { - Iterable oneThroughSix = asList(1, 2, 3, 4, 5, 6); - Iterable> groups = inGroupsOf(2, oneThroughSix); + Iterable oneThroughSix = asList(1, 2, 3, 4, 5, 6); + Iterable> groups = inGroupsOf(2, oneThroughSix); assertThat(groups, iterates(asList(1, 2), asList(3, 4), asList(5, 6))); } @Test public void lastGroupIsUnfinishedIfIterableSizeNotEvenlyDivisibleByK() { - Iterable oneThroughFive = asList(1, 2, 3, 4, 5); - Iterable> groups = inGroupsOf(2, oneThroughFive); + Iterable oneThroughFive = asList(1, 2, 3, 4, 5); + Iterable> groups = inGroupsOf(2, oneThroughFive); assertThat(groups, iterates(asList(1, 2), asList(3, 4), singletonList(5))); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java index ed75f2568..6ec5453a2 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java @@ -36,7 +36,7 @@ public class PartitionTest { @Test public void partitionsIterableIntoAsAndBs() { - Iterable strings = asList("one", "two", "three", "four", "five"); + Iterable strings = asList("one", "two", "three", "four", "five"); Tuple2, Iterable> partition = partition(s -> s.length() % 2 == 1 ? a(s) : b(s.length()), strings); assertThat(partition._1(), iterates("one", "two", "three")); @@ -45,8 +45,8 @@ public void partitionsIterableIntoAsAndBs() { @Test public void infiniteListSupport() { - Iterable> coproducts = cycle(a("left"), b(1)); - Tuple2, Iterable> partition = partition(id(), coproducts); + Iterable> coproducts = cycle(a("left"), b(1)); + Tuple2, Iterable> partition = partition(id(), coproducts); assertThat(take(3, partition._1()), iterates("left", "left", "left")); assertThat(take(3, partition._2()), iterates(1, 1, 1)); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SlideTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SlideTest.java index 6736b37ad..258e221b0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SlideTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/SlideTest.java @@ -45,8 +45,8 @@ public void kMustBeGreaterThan0() { @Test public void stackSafety() { - Integer stackBlowingNumber = 50000; - Iterable> xss = slide(2, take(stackBlowingNumber, iterate(x -> x + 1, 1))); + int stackBlowingNumber = 50_000; + Iterable> xss = slide(2, take(stackBlowingNumber, iterate(x -> x + 1, 1))); assertThat(drop(stackBlowingNumber - 2, xss), iterates(asList(49999, 50000))); } } \ 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 bfa4e7000..30a4172b3 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 @@ -33,7 +33,7 @@ public Fn1, Iterable> createTestObject() { @Test public void takesElementsWhilePredicateIsTrue() { Predicate lessThan3 = integer -> integer < 3; - Iterable numbers = takeWhile(lessThan3, asList(1, 2, 3, 4, 5)); + Iterable numbers = takeWhile(lessThan3, asList(1, 2, 3, 4, 5)); assertThat(numbers, iterates(1, 2)); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ZipTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ZipTest.java index 69f1545d7..ae7aa9d38 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ZipTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ZipTest.java @@ -27,9 +27,8 @@ public Fn1, Iterable>> createTestSubject } @Test - @SuppressWarnings("unchecked") public void zipsTwoIterablesTogether() { - Iterable odds = asList(1, 3, 5); + Iterable odds = asList(1, 3, 5); Iterable evens = asList(2, 4, 6); Iterable> numbers = zip(odds, evens); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElseTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElseTest.java index 70e1af6ab..f1e0895c6 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn4/IfThenElseTest.java @@ -11,9 +11,9 @@ public class IfThenElseTest { @Test public void standardLogic() { - Predicate even = x -> x % 2 == 0; - Fn1 inc = x -> x + 1; - Fn1 dec = x -> x - 1; + Predicate even = x -> x % 2 == 0; + Fn1 inc = x -> x + 1; + Fn1 dec = x -> x - 1; assertEquals((Integer) 3, ifThenElse(even, inc, dec, 2)); assertEquals((Integer) 0, ifThenElse(even, inc, dec, 1)); diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java index 396982cdc..23abb2ce7 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/MappingIteratorTest.java @@ -13,8 +13,8 @@ public class MappingIteratorTest { @Test public void nextProducesMappedResult() { - Fn1 stringToLength = String::length; - List words = asList("foo", "bar"); + Fn1 stringToLength = String::length; + List words = asList("foo", "bar"); MappingIterator mappingIterator = new MappingIterator<>(stringToLength, words.iterator()); assertThat(mappingIterator.next(), is(3)); diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java index 70ba8953f..aae11165b 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedTakingIteratorTest.java @@ -16,14 +16,14 @@ public class PredicatedTakingIteratorTest { @Test public void hasNextIfPredicateSucceedsForNextElement() { - Iterable words = asList("four", "three", "two", "one"); + Iterable words = asList("four", "three", "two", "one"); PredicatedTakingIterator predicatedTakingIterator = new PredicatedTakingIterator<>(HAS_FOUR_LETTERS, words.iterator()); assertThat(predicatedTakingIterator.hasNext(), is(true)); } @Test public void stopsTakingAfterFirstPredicateFailure() { - Iterable words = asList("once", "upon", "a", "time"); + Iterable words = asList("once", "upon", "a", "time"); PredicatedTakingIterator predicatedTakingIterator = new PredicatedTakingIterator<>(HAS_FOUR_LETTERS, words.iterator()); predicatedTakingIterator.next(); predicatedTakingIterator.next(); @@ -32,14 +32,14 @@ public void stopsTakingAfterFirstPredicateFailure() { @Test public void doesNotHaveNextIfFirstElementFailsPredicate() { - Iterable words = asList("I", "have", "a", "dream"); + Iterable words = asList("I", "have", "a", "dream"); PredicatedTakingIterator predicatedTakingIterator = new PredicatedTakingIterator<>(HAS_FOUR_LETTERS, words.iterator()); assertThat(predicatedTakingIterator.hasNext(), is(false)); } @Test public void doesNotHaveNextIfTakenAllElements() { - Iterable words = asList("four", "four"); + Iterable words = asList("four", "four"); PredicatedTakingIterator predicatedTakingIterator = new PredicatedTakingIterator<>(HAS_FOUR_LETTERS, words.iterator()); predicatedTakingIterator.next(); predicatedTakingIterator.next(); @@ -48,14 +48,14 @@ public void doesNotHaveNextIfTakenAllElements() { @Test(expected = NoSuchElementException.class) public void throwsExceptionIfNextAfterFailedPredicate() { - Iterable words = singletonList("no"); + Iterable words = singletonList("no"); PredicatedTakingIterator predicatedTakingIterator = new PredicatedTakingIterator<>(HAS_FOUR_LETTERS, words.iterator()); predicatedTakingIterator.next(); } @Test public void takesEverythingIfPredicateNeverFails() { - Iterable words = singletonList("yeah"); + Iterable words = singletonList("yeah"); PredicatedTakingIterator predicatedTakingIterator = new PredicatedTakingIterator<>(HAS_FOUR_LETTERS, words.iterator()); assertThat(predicatedTakingIterator.next(), is("yeah")); assertThat(predicatedTakingIterator.hasNext(), is(false)); diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java index d22dd8138..b405da88b 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TakingIteratorTest.java @@ -13,14 +13,14 @@ public class TakingIteratorTest { @Test public void hasNextBeforeTakingAnyElements() { - List numbers = asList(1, 2, 3, 4, 5); + List numbers = asList(1, 2, 3, 4, 5); TakingIterator takingIterator = new TakingIterator<>(3, numbers.iterator()); assertThat(takingIterator.hasNext(), is(true)); } @Test public void doesNotHaveNextIfTakenEnoughElements() { - List vowels = asList('a', 'e', 'i', 'o', 'u'); + List vowels = asList('a', 'e', 'i', 'o', 'u'); TakingIterator takingIterator = new TakingIterator<>(3, vowels.iterator()); takingIterator.next(); takingIterator.next(); @@ -30,7 +30,7 @@ public void doesNotHaveNextIfTakenEnoughElements() { @Test public void doesNotHaveNextIfTakenAllOfIterable() { - List words = asList("we", "the", "people"); + List words = asList("we", "the", "people"); TakingIterator takingIterator = new TakingIterator<>(4, words.iterator()); takingIterator.next(); takingIterator.next(); diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java index 85743e4b2..30fbfb9df 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java @@ -1,7 +1,6 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; -import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/MonoidTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/MonoidTest.java index 1282b4f66..87cfced3e 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/MonoidTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/MonoidTest.java @@ -15,19 +15,19 @@ public class MonoidTest { @Test public void reduceLeft() { - Monoid sum = monoid((x, y) -> x + y, 0); + Monoid sum = monoid(Integer::sum, 0); assertEquals((Integer) 6, sum.reduceLeft(asList(1, 2, 3))); } @Test public void reduceRight() { - Monoid sum = monoid((x, y) -> x + y, 0); + Monoid sum = monoid(Integer::sum, 0); assertEquals((Integer) 6, sum.reduceRight(asList(1, 2, 3))); } @Test public void foldMap() { - Monoid sum = monoid((x, y) -> x + y, 0); + Monoid sum = monoid(Integer::sum, 0); List> maybeInts = asList(just(1), just(2), nothing(), just(3), nothing()); assertEquals((Integer) 6, sum.foldMap(maybeX -> maybeX.orElse(0), maybeInts)); } diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AndTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AndTest.java index d78aaf702..25b10aca9 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AndTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AndTest.java @@ -27,7 +27,7 @@ public void monoid() { @Test(timeout = 500) public void shortCircuiting() { Iterable bools = cons(false, repeat(true)); - And and = and(); + And and = and(); assertEquals(false, and.foldLeft(false, bools)); assertEquals(false, and.foldLeft(true, bools)); diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/CollapseTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/CollapseTest.java index 1e0f36e9e..5c42de619 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/CollapseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/CollapseTest.java @@ -5,14 +5,15 @@ import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.monoid.builtin.Collapse.collapse; +import static com.jnape.palatable.lambda.monoid.builtin.Join.join; import static org.junit.Assert.assertEquals; public class CollapseTest { @Test public void monoid() { - Monoid join = Monoid.monoid((x, y) -> x + y, ""); - Monoid add = Monoid.monoid((x, y) -> x + y, 0); + Monoid join = join(); + Monoid add = Monoid.monoid(Integer::sum, 0); Collapse collapse = collapse(); diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/FirstTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/FirstTest.java index 76675e52e..4b5ee5960 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/FirstTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/FirstTest.java @@ -29,7 +29,7 @@ public void monoid() { @Test(timeout = 500) public void shortCircuiting() { Iterable> maybeInts = repeat(just(1)); - First first = First.first(); + First first = First.first(); assertEquals(just(1), first.foldLeft(nothing(), maybeInts)); assertEquals(just(1), first.foldLeft(just(1), maybeInts)); diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/LeftAnyTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/LeftAnyTest.java index dc6692ed0..24426ca71 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/LeftAnyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/LeftAnyTest.java @@ -13,7 +13,7 @@ public class LeftAnyTest { @Test public void monoid() { LeftAny leftAny = leftAny(); - Monoid join = Monoid.monoid((x, y) -> x + y, ""); + Monoid join = Monoid.monoid((x, y) -> x + y, ""); assertEquals(left(""), leftAny.apply(join).identity()); assertEquals(left("foo"), leftAny.apply(join).apply(left("foo"), right(1))); diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeMapsTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeMapsTest.java index be871be21..fe27f4833 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeMapsTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeMapsTest.java @@ -18,7 +18,8 @@ import static org.junit.Assert.assertTrue; public class MergeMapsTest { - private static final Semigroup ADD = (x, y) -> x + y; + private static final Semigroup ADD = Integer::sum; + private Monoid> merge; @Before @@ -36,8 +37,8 @@ public void monoid() { assertEquals(singletonMap("foo", 1), merge.apply(emptyMap(), singletonMap("foo", 1))); assertEquals(singletonMap("foo", 1), merge.apply(singletonMap("foo", 1), emptyMap())); assertEquals(singletonMap("foo", 2), - merge.apply(singletonMap("foo", 1), singletonMap("foo", 1))); + merge.apply(singletonMap("foo", 1), singletonMap("foo", 1))); assertEquals(toMap(HashMap::new, asList(tuple("foo", 1), tuple("bar", 1))), - merge.apply(singletonMap("foo", 1), singletonMap("bar", 1))); + merge.apply(singletonMap("foo", 1), singletonMap("bar", 1))); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/OrTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/OrTest.java index d421c1e5d..0e22e20bd 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/OrTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/OrTest.java @@ -27,7 +27,7 @@ public void monoid() { @Test(timeout = 500) public void shortCircuiting() { Iterable bools = cons(true, repeat(false)); - Or or = or(); + Or or = or(); assertEquals(true, or.foldLeft(false, bools)); assertEquals(true, or.foldLeft(true, bools)); diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/PresentTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/PresentTest.java index 98b1f952d..49eca1df6 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/PresentTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/PresentTest.java @@ -12,8 +12,8 @@ public class PresentTest { @Test public void monoid() { - Present present = present(); - Semigroup addition = (x, y) -> x + y; + Present present = present(); + Semigroup addition = Integer::sum; assertEquals(just(3), present.apply(addition, just(1), just(2))); assertEquals(just(1), present.apply(addition, nothing(), just(1))); diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/PutAllTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/PutAllTest.java index bd664b01d..5d3f90215 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/PutAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/PutAllTest.java @@ -19,8 +19,8 @@ public void identity() { @Test public void monoid() { - TypeSafeKey stringKey = typeSafeKey(); - TypeSafeKey intKey = typeSafeKey(); + TypeSafeKey stringKey = typeSafeKey(); + TypeSafeKey intKey = typeSafeKey(); HMap x = singletonHMap(stringKey, "string"); HMap y = singletonHMap(intKey, 1); diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RightAnyTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RightAnyTest.java index 96a4d4e8a..730438ace 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RightAnyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/RightAnyTest.java @@ -13,7 +13,7 @@ public class RightAnyTest { @Test public void monoid() { RightAny rightAny = rightAny(); - Monoid add = Monoid.monoid((x, y) -> x + y, 0); + Monoid add = Monoid.monoid(Integer::sum, 0); assertEquals(right(0), rightAny.apply(add).identity()); assertEquals(right(1), rightAny.apply(add).apply(right(1), left("foo"))); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java index 7df46e6e2..5ef25395e 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java @@ -12,8 +12,8 @@ public class AbsentTest { @Test public void semigroup() { - Absent absent = absent(); - Semigroup addition = (x, y) -> x + y; + Absent absent = absent(); + Semigroup addition = Integer::sum; assertEquals(just(3), absent.apply(addition, just(1), just(2))); assertEquals(nothing(), absent.apply(addition, nothing(), just(1))); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/CollapseTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/CollapseTest.java index face88111..cca4de936 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/CollapseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/CollapseTest.java @@ -4,6 +4,7 @@ import org.junit.Test; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.monoid.builtin.Join.join; import static com.jnape.palatable.lambda.semigroup.builtin.Collapse.collapse; import static org.junit.Assert.assertEquals; @@ -11,8 +12,8 @@ public class CollapseTest { @Test public void semigroup() { - Semigroup join = (x, y) -> x + y; - Semigroup add = (x, y) -> x + y; + Semigroup join = join(); + Semigroup add = Integer::sum; Collapse collapse = collapse(); assertEquals(tuple("foobar", 3), collapse.apply(join, add, tuple("foo", 1), tuple("bar", 2))); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAnyTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAnyTest.java index 98026177b..2e0cd7ea0 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAnyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/LeftAnyTest.java @@ -13,7 +13,7 @@ public class LeftAnyTest { @Test public void semigroup() { LeftAny leftAny = leftAny(); - Semigroup join = (x, y) -> x + y; + Semigroup join = (x, y) -> x + y; assertEquals(left("foo"), leftAny.apply(join).apply(left("foo"), right(1))); assertEquals(left("foo"), leftAny.apply(join).apply(right(1), left("foo"))); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MergeTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MergeTest.java index c867c1302..5cd397cd4 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MergeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MergeTest.java @@ -6,6 +6,7 @@ import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.monoid.builtin.Join.join; import static com.jnape.palatable.lambda.semigroup.builtin.Merge.merge; import static org.junit.Assert.assertEquals; @@ -13,8 +14,8 @@ public class MergeTest { @Test public void semigroup() { - Semigroup join = (x, y) -> x + y; - Semigroup add = (x, y) -> x + y; + Semigroup join = join(); + Semigroup add = Integer::sum; Semigroup> merge = merge(join, add); assertEquals(left("onetwo"), merge.apply(left("one"), left("two"))); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RightAnyTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RightAnyTest.java index ec234090e..46d8e5f5a 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RightAnyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/RightAnyTest.java @@ -13,7 +13,7 @@ public class RightAnyTest { @Test public void semigroup() { RightAny rightAny = rightAny(); - Semigroup add = (x, y) -> x + y; + Semigroup add = Integer::sum; assertEquals(right(1), rightAny.apply(add).apply(right(1), left("foo"))); assertEquals(right(1), rightAny.apply(add).apply(left("foo"), right(1))); From 66533aa766eaacb25ac91abdec97bff1dc106875 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 8 Sep 2019 16:20:36 -0500 Subject: [PATCH 235/348] Housekeeping --- .../com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java index e4c5aeda1..adb903523 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Eq.java @@ -3,6 +3,8 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; +import java.util.Objects; + /** * Type-safe equality in function form; uses {@link Object#equals}, not ==. * @@ -17,7 +19,7 @@ private Eq() { @Override public Boolean checkedApply(A x, A y) { - return x == null ? y == null : x.equals(y); + return Objects.equals(x, y); } @SuppressWarnings("unchecked") From f2fb98a85be0fc41e555e3e954300dfdf7a30e76 Mon Sep 17 00:00:00 2001 From: John Napier Date: Tue, 10 Sep 2019 13:33:01 -0500 Subject: [PATCH 236/348] Adding Github build action --- .github/workflows/maven.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 000000000..9bf714670 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,30 @@ +name: Java CI + +on: [push] + +jobs: + build-java-1.8: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Maven + run: mvn clean verify + + build-java-11: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Build with Maven + run: mvn clean verify From a32ddcbe0eac4a792fb9ca8180d02b744a3c7e61 Mon Sep 17 00:00:00 2001 From: John Napier Date: Tue, 10 Sep 2019 13:34:34 -0500 Subject: [PATCH 237/348] sigh... --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 9bf714670..2f7615ccb 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -3,7 +3,7 @@ name: Java CI on: [push] jobs: - build-java-1.8: + build-java-1_8: runs-on: ubuntu-latest From 698259129231a2cd8f7c17a69815da6d3e7f82bc Mon Sep 17 00:00:00 2001 From: John Napier Date: Tue, 10 Sep 2019 13:43:14 -0500 Subject: [PATCH 238/348] Adding Github Actions badge to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 65ba3cd42..c56db81be 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ λ ====== [![Build Status](https://travis-ci.com/palatable/lambda.svg?branch=master)](https://travis-ci.com/palatable/lambda) +[![Actions Status](https://github.com/palatable/lambda/workflows/Java%20CI/badge.svg)](https://github.com/palatable/lambda/actions) [![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda) [![Join the chat at https://gitter.im/palatable/lambda](https://badges.gitter.im/palatable/lambda.svg)](https://gitter.im/palatable/lambda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Floobits Status](https://floobits.com/jnape/lambda.svg)](https://floobits.com/jnape/lambda/redirect) From 6e95041b01dbd93f7f7409fe68c4bbd4fda45edb Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 1 Aug 2019 18:33:20 -0500 Subject: [PATCH 239/348] - initial MonadRec interface - MonadRec impls for Identity, Either, and Maybe - laws --- .../jnape/palatable/lambda/adt/Either.java | 15 +++++++ .../com/jnape/palatable/lambda/adt/Maybe.java | 15 +++++++ .../lambda/functor/builtin/Identity.java | 23 +++++++--- .../palatable/lambda/monad/MonadRec.java | 43 +++++++++++++++++++ .../palatable/lambda/adt/EitherTest.java | 9 +++- .../jnape/palatable/lambda/adt/MaybeTest.java | 5 ++- .../lambda/functor/builtin/IdentityTest.java | 3 +- .../java/testsupport/traits/MonadRecLaws.java | 25 +++++++++++ 8 files changed, 129 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java create mode 100644 src/test/java/testsupport/traits/MonadRecLaws.java 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 9437f8be9..0734b413b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -5,6 +5,7 @@ import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; @@ -13,6 +14,7 @@ import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadError; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; @@ -20,6 +22,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.io.IO.io; import static java.util.Arrays.asList; @@ -35,6 +39,7 @@ public abstract class Either implements CoProduct2>, MonadError>, + MonadRec>, Traversable>, Bifunctor> { @@ -134,6 +139,16 @@ public Either flatMap(Fn1>::coerce)); } + /** + * {@inheritDoc} + */ + @Override + public Either trampolineM(Fn1, Either>> fn) { + return match(Either::left, trampoline(a -> fn.apply(a).>>coerce() + .match(l -> terminate(left(l)), + aOrB -> aOrB.fmap(Either::right)))); + } + @Override public final Either invert() { return match(Either::right, Either::left); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java index cc5b18899..dc5595983 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Maybe.java @@ -7,6 +7,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; @@ -14,6 +15,7 @@ import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadError; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; @@ -24,6 +26,8 @@ import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.io.IO.io; @@ -37,6 +41,7 @@ public abstract class Maybe implements CoProduct2>, MonadError>, + MonadRec>, Traversable> { private Maybe() { @@ -194,6 +199,16 @@ public final Maybe flatMap(Fn1>> f return match(constantly(nothing()), f.fmap(Monad>::coerce)); } + /** + * {@inheritDoc} + */ + @Override + public Maybe trampolineM(Fn1, Maybe>> fn) { + return match(constantly(nothing()), trampoline(a -> fn.apply(a).>>coerce() + .match(constantly(terminate(nothing())), + aOrB -> aOrB.fmap(Maybe::just)))); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java index 0a48147cb..3ee6a0dbb 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Identity.java @@ -1,19 +1,23 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; + /** * A functor over some value of type A that can be mapped over and retrieved later. * * @param the value type */ -public final class Identity implements Monad>, Traversable> { +public final class Identity implements MonadRec>, Traversable> { private final A a; @@ -43,7 +47,7 @@ public Identity flatMap(Fn1>> f */ @Override public Identity fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -68,7 +72,7 @@ public Identity zip(Applicative, Identity> @Override public Lazy> lazyZip( Lazy, Identity>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -76,7 +80,7 @@ public Lazy> lazyZip( */ @Override public Identity discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -84,7 +88,7 @@ public Identity discardL(Applicative> appB) { */ @Override public Identity discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -98,6 +102,15 @@ AppTrav extends Applicative> AppTrav traverse(Fn1 Identity trampolineM(Fn1, Identity>> fn) { + return new Identity<>(trampoline(a -> fn.apply(a).>>coerce().runIdentity(), + runIdentity())); + } + @Override public boolean equals(Object other) { return other instanceof Identity && Objects.equals(a, ((Identity) other).a); diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java new file mode 100644 index 000000000..fd887da18 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java @@ -0,0 +1,43 @@ +package com.jnape.palatable.lambda.monad; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; + +public interface MonadRec> extends Monad { + + MonadRec trampolineM(Fn1, M>> fn); + + @Override + MonadRec flatMap(Fn1> f); + + @Override + MonadRec pure(B b); + + @Override + default MonadRec fmap(Fn1 fn) { + return Monad.super.fmap(fn).coerce(); + } + + @Override + default MonadRec zip(Applicative, M> appFn) { + return Monad.super.zip(appFn).coerce(); + } + + @Override + default Lazy> lazyZip( + Lazy, M>> lazyAppFn) { + return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + } + + @Override + default MonadRec discardL(Applicative appB) { + return Monad.super.discardL(appB).coerce(); + } + + @Override + default MonadRec discardR(Applicative appB) { + return Monad.super.discardR(appB).coerce(); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java index 40ec74e61..50921161d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/EitherTest.java @@ -12,6 +12,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import java.util.concurrent.atomic.AtomicInteger; @@ -35,7 +36,13 @@ public class EitherTest { @Rule public ExpectedException thrown = ExpectedException.none(); - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + BifunctorLaws.class, + TraversableLaws.class, + MonadRecLaws.class}) public Subjects> testSubjects() { return subjects(left("foo"), right(1)); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java index 636e9b784..6668dbc19 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/MaybeTest.java @@ -10,6 +10,7 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import java.util.Optional; @@ -32,7 +33,7 @@ @RunWith(Traits.class) public class MaybeTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, TraversableLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, TraversableLaws.class, MonadLaws.class, MonadRecLaws.class}) public Subjects> testSubject() { return subjects(Maybe.nothing(), just(1)); } @@ -114,7 +115,7 @@ public void nothingOrThrow() { @Test public void divergesIntoChoice3() { assertEquals(Choice3.a(UNIT), nothing().diverge()); - assertEquals(Choice3.b(1), just(1).diverge()); + assertEquals(Choice3.b(1), just(1).diverge()); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java index 91b57457b..80e48fc15 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java @@ -7,6 +7,7 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; @@ -15,7 +16,7 @@ @RunWith(Traits.class) public class IdentityTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class, MonadRecLaws.class}) public Identity testSubject() { return new Identity<>(""); } diff --git a/src/test/java/testsupport/traits/MonadRecLaws.java b/src/test/java/testsupport/traits/MonadRecLaws.java new file mode 100644 index 000000000..2551e9ecc --- /dev/null +++ b/src/test/java/testsupport/traits/MonadRecLaws.java @@ -0,0 +1,25 @@ +package testsupport.traits; + +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.traitor.traits.Trait; + +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.recurse; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; + +public class MonadRecLaws> implements Trait> { + + @Override + public void test(MonadRec monadRec) { + + + boolean equals = monadRec.pure(STACK_EXPLODING_NUMBER) + .equals(monadRec.pure(0) + .trampolineM(x -> monadRec.pure(x < STACK_EXPLODING_NUMBER + ? recurse(x + 1) + : terminate(x)))); + if (!equals) + throw new AssertionError("Expected m.pure(" + STACK_EXPLODING_NUMBER + ") == " + + "m.pure(0).trampolineM(f)"); + } +} From 73dc6b44cf3c44d585f235d90f409a67dcf05910 Mon Sep 17 00:00:00 2001 From: Siddhartha Duri Date: Thu, 1 Aug 2019 21:23:56 -0500 Subject: [PATCH 240/348] MonadRec implementation for Choice4 --- .../palatable/lambda/adt/choice/Choice4.java | 27 +++++++++++++++---- .../lambda/adt/choice/Choice4Test.java | 24 ++++++++++------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index d6ce118b2..cff8233bc 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -6,17 +6,21 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple4; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into4.into4; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** @@ -31,7 +35,7 @@ */ public abstract class Choice4 implements CoProduct4>, - Monad>, + MonadRec>, Bifunctor>, Traversable> { @@ -70,7 +74,7 @@ public Choice3 converge(Fn1 */ @Override public final Choice4 fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -108,7 +112,7 @@ public Choice4 pure(E e) { */ @Override public Choice4 zip(Applicative, Choice4> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -128,7 +132,7 @@ public Lazy> lazyZip( */ @Override public Choice4 discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -136,7 +140,7 @@ public Choice4 discardL(Applicative> appB */ @Override public Choice4 discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -161,6 +165,19 @@ AppTrav extends Applicative> AppTrav traverse(Fn1 fn.apply(d).>fmap(Choice4::d).fmap(Functor::coerce).coerce()); } + @Override + public Choice4 trampolineM( + Fn1, Choice4>> fn) { + return match(Choice4::a, + Choice4::b, + Choice4::c, + trampoline(d -> fn.apply(d).>>coerce() + .match(a -> terminate(a(a)), + b -> terminate(b(b)), + c -> terminate(c(c)), + dOrE -> dOrE.fmap(Choice4::d)))); + } + /** * Static factory method for wrapping a value of type A in a {@link Choice4}. * diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java index 4cc5735bf..630a8979e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice4Test.java @@ -10,6 +10,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.choice.Choice4.a; @@ -36,25 +37,30 @@ public void setUp() { d = d(4D); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + BifunctorLaws.class, + TraversableLaws.class, + MonadRecLaws.class}) public Subjects> testSubjects() { return subjects(a("foo"), b(1), c(true), d('a')); } @Test public void convergeStaysInChoice() { - assertEquals(Choice3.a(1), a.converge(d -> Choice3.b(d.toString()))); - assertEquals(Choice3.b("two"), b.converge(d -> Choice3.b(d.toString()))); - assertEquals(Choice3.c(true), c.converge(d -> Choice3.b(d.toString()))); - assertEquals(Choice3.b("4.0"), d.converge(d -> Choice3.b(d.toString()))); + assertEquals(Choice3.a(1), a.converge(d -> Choice3.b(d.toString()))); + assertEquals(Choice3.b("two"), b.converge(d -> Choice3.b(d.toString()))); + assertEquals(Choice3.c(true), c.converge(d -> Choice3.b(d.toString()))); + assertEquals(Choice3.b("4.0"), d.converge(d -> Choice3.b(d.toString()))); } @Test public void divergeStaysInChoice() { - assertEquals(Choice5.a(1), a.diverge()); - assertEquals(Choice5.b("two"), b.diverge()); - assertEquals(Choice5.c(true), c.diverge()); - assertEquals(Choice5.d(4D), d.diverge()); + assertEquals(Choice5.a(1), a.diverge()); + assertEquals(Choice5.b("two"), b.diverge()); + assertEquals(Choice5.c(true), c.diverge()); + assertEquals(Choice5.d(4D), d.diverge()); } @Test From 83ed2c608fb28644171eaf1e9509c6ed17a2e02b Mon Sep 17 00:00:00 2001 From: George Shakhnazaryan Date: Thu, 1 Aug 2019 20:57:44 -0500 Subject: [PATCH 241/348] MonadRec implementation for Choice2 --- .../palatable/lambda/adt/choice/Choice2.java | 25 ++++++++++++++----- .../lambda/adt/choice/Choice2Test.java | 17 +++++++------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index 1766585d2..abfa5f4bb 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -6,17 +6,21 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** @@ -30,7 +34,7 @@ */ public abstract class Choice2 implements CoProduct2>, - Monad>, + MonadRec>, Bifunctor>, Traversable> { @@ -68,7 +72,7 @@ public Choice2 invert() { */ @Override public final Choice2 fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -109,14 +113,14 @@ public Choice2 pure(C c) { */ @Override public Choice2 zip(Applicative, Choice2> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** * {@inheritDoc} */ @Override - public Lazy>> lazyZip( + public Lazy> lazyZip( Lazy, Choice2>> lazyAppFn) { return match(a -> lazy(a(a)), b -> lazyAppFn.fmap(choiceF -> choiceF.fmap(f -> f.apply(b)).coerce())); @@ -127,7 +131,7 @@ public Choice2 zip(Applicative, Choice2 Choice2 discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -135,7 +139,7 @@ public Choice2 discardL(Applicative> appB) { */ @Override public Choice2 discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -146,6 +150,15 @@ public final Choice2 flatMap(Fn1 f.apply(b).coerce()); } + @Override + public Choice2 trampolineM(Fn1, Choice2>> fn) { + return match(Choice2::a, + trampoline(b -> fn.apply(b) + .>>coerce() + .match(a -> terminate(a(a)), + bOrC -> bOrC.fmap(Choice2::b)))); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java index b163be85d..234b423a6 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice2Test.java @@ -6,11 +6,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.traits.ApplicativeLaws; -import testsupport.traits.BifunctorLaws; -import testsupport.traits.FunctorLaws; -import testsupport.traits.MonadLaws; -import testsupport.traits.TraversableLaws; +import testsupport.traits.*; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; @@ -30,15 +26,20 @@ public void setUp() { b = b(true); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + BifunctorLaws.class, + TraversableLaws.class, + MonadRecLaws.class}) public Subjects> testSubjects() { return subjects(a("foo"), b(1)); } @Test public void divergeStaysInChoice() { - assertEquals(Choice3.a(1), a.diverge()); - assertEquals(Choice3.b(true), b.diverge()); + assertEquals(Choice3.a(1), a.diverge()); + assertEquals(Choice3.b(true), b.diverge()); } @Test From ae94ce6237370a8bf5e14fb2991a5942489a8f3e Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Sun, 4 Aug 2019 05:22:44 -0500 Subject: [PATCH 242/348] MonadRec Implementation for Choice3 --- .../palatable/lambda/adt/choice/Choice3.java | 26 +++++++++++++++---- .../lambda/adt/choice/Choice3Test.java | 8 ++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index c3fbb4fe4..ac495c99d 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -6,17 +6,21 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple3; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into3.into3; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** @@ -32,7 +36,19 @@ public abstract class Choice3 implements CoProduct3>, Monad>, Bifunctor>, - Traversable> { + Traversable>, + MonadRec> { + + /** + * {@inheritDoc} + */ + @Override + public Choice3 trampolineM(Fn1, Choice3>> fn) { + return flatMap(trampoline(c -> fn.apply(c).>>coerce() + .match(a -> terminate(a(a)), + b -> terminate(b(b)), + r -> r.fmap(Choice3::c)))); + } private Choice3() { } @@ -68,7 +84,7 @@ public final Choice2 converge(Fn1 */ @Override public final Choice3 fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -109,7 +125,7 @@ public Choice3 pure(D d) { */ @Override public Choice3 zip(Applicative, Choice3> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -128,7 +144,7 @@ public Lazy> lazyZip( */ @Override public Choice3 discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -136,7 +152,7 @@ public Choice3 discardL(Applicative> appB) { */ @Override public Choice3 discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java index e096f717a..8454d9f67 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice3Test.java @@ -6,11 +6,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.traits.ApplicativeLaws; -import testsupport.traits.BifunctorLaws; -import testsupport.traits.FunctorLaws; -import testsupport.traits.MonadLaws; -import testsupport.traits.TraversableLaws; +import testsupport.traits.*; import static com.jnape.palatable.lambda.adt.choice.Choice3.a; import static com.jnape.palatable.lambda.adt.choice.Choice3.b; @@ -33,7 +29,7 @@ public void setUp() { c = Choice3.c(true); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class, MonadRecLaws.class}) public Subjects> testSubjects() { return subjects(a("foo"), b(1), c(true)); } From ad16a7575a22433f4c875bee015002207ae17b3a Mon Sep 17 00:00:00 2001 From: Michael A Date: Sun, 4 Aug 2019 21:23:26 -0500 Subject: [PATCH 243/348] MonadRec implementation for Choice5 --- .../palatable/lambda/adt/choice/Choice5.java | 31 ++++++++++++++++--- .../lambda/adt/choice/Choice5Test.java | 19 +++++------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index 593d31b83..a87a2b1d5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -6,16 +6,20 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple5; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into5.into5; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** @@ -31,7 +35,7 @@ */ public abstract class Choice5 implements CoProduct5>, - Monad>, + MonadRec>, Bifunctor>, Traversable> { @@ -70,7 +74,7 @@ public Choice4 converge(Fn1 Choice5 fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -111,7 +115,7 @@ public Choice5 pure(F f) { */ @Override public Choice5 zip(Applicative, Choice5> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -132,7 +136,7 @@ public Lazy> lazyZip( */ @Override public Choice5 discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -140,7 +144,7 @@ public Choice5 discardL(Applicative */ @Override public Choice5 discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -151,6 +155,23 @@ public Choice5 flatMap(Fn1 f.apply(e).coerce()); } + /** + * {@inheritDoc} + */ + @Override + public Choice5 trampolineM(Fn1, Choice5>> fn) { + return match(Choice5::a, + Choice5::b, + Choice5::c, + Choice5::d, + trampoline(e -> fn.apply(e).>>coerce().match( + a -> terminate(Choice5.a(a)), + b -> terminate(Choice5.b(b)), + c -> terminate(Choice5.c(c)), + d -> terminate(Choice5.d(d)), + eRec -> eRec.fmap(Choice5::e)))); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java index dc4fef3da..b078dea7d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice5Test.java @@ -6,17 +6,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.traits.ApplicativeLaws; -import testsupport.traits.BifunctorLaws; -import testsupport.traits.FunctorLaws; -import testsupport.traits.MonadLaws; -import testsupport.traits.TraversableLaws; +import testsupport.traits.*; -import static com.jnape.palatable.lambda.adt.choice.Choice5.a; -import static com.jnape.palatable.lambda.adt.choice.Choice5.b; -import static com.jnape.palatable.lambda.adt.choice.Choice5.c; -import static com.jnape.palatable.lambda.adt.choice.Choice5.d; -import static com.jnape.palatable.lambda.adt.choice.Choice5.e; +import static com.jnape.palatable.lambda.adt.choice.Choice5.*; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -39,7 +31,12 @@ public void setUp() { e = e('z'); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + BifunctorLaws.class, + TraversableLaws.class, + MonadRecLaws.class}) public Subjects> testSubjects() { return subjects(Choice5.a("foo"), Choice5.b(1), Choice5.c(true), Choice5.d('a'), Choice5.e(2d)); } From 3afdabc01c2551a50d41cc85acc5f9689afce1ab Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 3 Aug 2019 15:51:08 -0500 Subject: [PATCH 244/348] - Adding MonadRec instance for remaining monads - Better documentation --- .../com/jnape/palatable/lambda/adt/Try.java | 16 +++++ .../palatable/lambda/adt/choice/Choice2.java | 10 ++-- .../palatable/lambda/adt/choice/Choice3.java | 23 ++++---- .../palatable/lambda/adt/choice/Choice4.java | 25 ++++---- .../palatable/lambda/adt/choice/Choice5.java | 19 +++--- .../palatable/lambda/adt/choice/Choice6.java | 29 ++++++++-- .../palatable/lambda/adt/choice/Choice7.java | 30 ++++++++-- .../palatable/lambda/adt/choice/Choice8.java | 31 ++++++++-- .../palatable/lambda/adt/hlist/Tuple2.java | 23 ++++++-- .../jnape/palatable/lambda/functions/Fn1.java | 20 +++++-- .../lambda/functions/specialized/Lift.java | 8 +-- .../lambda/functor/builtin/Const.java | 23 ++++++-- .../lambda/functor/builtin/Lazy.java | 21 +++++-- .../lambda/functor/builtin/Market.java | 24 +++++++- .../lambda/functor/builtin/State.java | 30 ++++++++-- .../lambda/functor/builtin/Tagged.java | 25 +++++--- .../com/jnape/palatable/lambda/io/IO.java | 14 ++++- .../palatable/lambda/monad/MonadBase.java | 16 ++--- .../palatable/lambda/monad/MonadError.java | 6 ++ .../palatable/lambda/monad/MonadRec.java | 49 ++++++++++++++++ .../lambda/monad/transformer/MonadT.java | 19 +++--- .../monad/transformer/builtin/EitherT.java | 39 +++++++++---- .../monad/transformer/builtin/IdentityT.java | 43 ++++++++++---- .../monad/transformer/builtin/LazyT.java | 38 ++++++++---- .../monad/transformer/builtin/MaybeT.java | 40 +++++++++---- .../monad/transformer/builtin/ReaderT.java | 46 ++++++++------- .../monad/transformer/builtin/StateT.java | 58 ++++++++++++------- .../monad/transformer/builtin/WriterT.java | 34 +++++++---- .../jnape/palatable/lambda/optics/Iso.java | 24 ++++++-- .../jnape/palatable/lambda/optics/Lens.java | 26 +++++++-- .../jnape/palatable/lambda/optics/Prism.java | 27 +++++++-- .../jnape/palatable/lambda/adt/TryTest.java | 3 +- .../lambda/adt/choice/Choice6Test.java | 9 ++- .../lambda/adt/choice/Choice7Test.java | 9 ++- .../lambda/adt/choice/Choice8Test.java | 9 ++- .../lambda/adt/hlist/Tuple2Test.java | 9 ++- .../palatable/lambda/functions/Fn1Test.java | 2 + .../lambda/functor/builtin/ConstTest.java | 9 ++- .../lambda/functor/builtin/LazyTest.java | 3 +- .../lambda/functor/builtin/MarketTest.java | 3 +- .../lambda/functor/builtin/StateTest.java | 2 + .../lambda/functor/builtin/TaggedTest.java | 3 +- .../com/jnape/palatable/lambda/io/IOTest.java | 3 +- .../transformer/builtin/EitherTTest.java | 8 ++- .../transformer/builtin/IdentityTTest.java | 3 +- .../monad/transformer/builtin/LazyTTest.java | 3 +- .../monad/transformer/builtin/MaybeTTest.java | 3 +- .../transformer/builtin/ReaderTTest.java | 3 +- .../monad/transformer/builtin/StateTTest.java | 2 + .../transformer/builtin/WriterTTest.java | 7 ++- .../palatable/lambda/optics/IsoTest.java | 3 +- .../palatable/lambda/optics/LensTest.java | 3 +- .../palatable/lambda/optics/PrismTest.java | 3 +- .../java/testsupport/traits/MonadRecLaws.java | 44 +++++++++----- 54 files changed, 729 insertions(+), 253 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/Try.java b/src/main/java/com/jnape/palatable/lambda/adt/Try.java index aeb56779c..90cd28091 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Try.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Try.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.builtin.fn1.Downcast; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functions.specialized.SideEffect; @@ -11,6 +12,7 @@ import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadError; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; @@ -20,6 +22,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.internal.Runtime.throwChecked; @@ -32,6 +36,7 @@ */ public abstract class Try implements MonadError>, + MonadRec>, Traversable>, CoProduct2> { @@ -239,6 +244,17 @@ public Try discardR(Applicative> appB) { return MonadError.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Try trampolineM(Fn1, Try>> fn) { + return flatMap(trampoline(a -> fn.apply(a).>>coerce().match( + t -> terminate(failure(t)), + aOrB -> aOrB.fmap(Try::success) + ))); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index abfa5f4bb..460e1fa40 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -150,13 +150,15 @@ public final Choice2 flatMap(Fn1 f.apply(b).coerce()); } + /** + * {@inheritDoc} + */ @Override public Choice2 trampolineM(Fn1, Choice2>> fn) { return match(Choice2::a, - trampoline(b -> fn.apply(b) - .>>coerce() - .match(a -> terminate(a(a)), - bOrC -> bOrC.fmap(Choice2::b)))); + trampoline(b -> fn.apply(b).>>coerce() + .match(a -> terminate(a(a)), + bOrC -> bOrC.fmap(Choice2::b)))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index ac495c99d..1d4263406 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -39,17 +39,6 @@ public abstract class Choice3 implements Traversable>, MonadRec> { - /** - * {@inheritDoc} - */ - @Override - public Choice3 trampolineM(Fn1, Choice3>> fn) { - return flatMap(trampoline(c -> fn.apply(c).>>coerce() - .match(a -> terminate(a(a)), - b -> terminate(b(b)), - r -> r.fmap(Choice3::c)))); - } - private Choice3() { } @@ -163,6 +152,18 @@ public Choice3 flatMap(Fn1 f.apply(c).coerce()); } + /** + * {@inheritDoc} + */ + @Override + public Choice3 trampolineM( + Fn1, Choice3>> fn) { + return flatMap(trampoline(c -> fn.apply(c).>>coerce() + .match(a -> terminate(a(a)), + b -> terminate(b(b)), + r -> r.fmap(Choice3::c)))); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index cff8233bc..d35fd3756 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -154,17 +154,6 @@ public Choice4 flatMap(Fn1, TravB extends Traversable>, - AppTrav extends Applicative> AppTrav traverse(Fn1> fn, - Fn1 pure) { - return match(a -> pure.apply((TravB) Choice4.a(a)).coerce(), - b -> pure.apply((TravB) Choice4.b(b)).coerce(), - c -> pure.apply((TravB) Choice4.c(c)), - d -> fn.apply(d).>fmap(Choice4::d).fmap(Functor::coerce).coerce()); - } - @Override public Choice4 trampolineM( Fn1, Choice4>> fn) { @@ -178,6 +167,20 @@ public Choice4 trampolineM( dOrE -> dOrE.fmap(Choice4::d)))); } + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public , TravB extends Traversable>, + AppTrav extends Applicative> AppTrav traverse(Fn1> fn, + Fn1 pure) { + return match(a -> pure.apply((TravB) Choice4.a(a)).coerce(), + b -> pure.apply((TravB) Choice4.b(b)).coerce(), + c -> pure.apply((TravB) Choice4.c(c)), + d -> fn.apply(d).>fmap(Choice4::d).fmap(Functor::coerce).coerce()); + } + /** * Static factory method for wrapping a value of type A in a {@link Choice4}. * diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index a87a2b1d5..251f7a6c6 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -159,17 +159,14 @@ public Choice5 flatMap(Fn1 Choice5 trampolineM(Fn1, Choice5>> fn) { - return match(Choice5::a, - Choice5::b, - Choice5::c, - Choice5::d, - trampoline(e -> fn.apply(e).>>coerce().match( - a -> terminate(Choice5.a(a)), - b -> terminate(Choice5.b(b)), - c -> terminate(Choice5.c(c)), - d -> terminate(Choice5.d(d)), - eRec -> eRec.fmap(Choice5::e)))); + public Choice5 trampolineM( + Fn1, Choice5>> fn) { + return flatMap(trampoline(e -> fn.apply(e).>>coerce().match( + a -> terminate(Choice5.a(a)), + b -> terminate(Choice5.b(b)), + c -> terminate(Choice5.c(c)), + d -> terminate(Choice5.d(d)), + eRec -> eRec.fmap(Choice5::e)))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index 7ca0c0082..b87de1a97 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -6,16 +6,20 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple6; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into6.into6; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** @@ -32,7 +36,7 @@ */ public abstract class Choice6 implements CoProduct6>, - Monad>, + MonadRec>, Bifunctor>, Traversable> { @@ -71,7 +75,7 @@ public Choice5 converge(Fn1 Choice6 fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -115,7 +119,7 @@ public Choice6 pure(G g) { @Override public Choice6 zip( Applicative, Choice6> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -137,7 +141,7 @@ public Lazy> lazyZip( */ @Override public Choice6 discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -145,7 +149,7 @@ public Choice6 discardL(Applicative Choice6 discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -156,6 +160,21 @@ public Choice6 flatMap(Fn1 fn.apply(f).coerce()); } + /** + * {@inheritDoc} + */ + @Override + public Choice6 trampolineM( + Fn1, Choice6>> fn) { + return flatMap(trampoline(f -> fn.apply(f).>>coerce().match( + a -> terminate(Choice6.a(a)), + b -> terminate(Choice6.b(b)), + c -> terminate(Choice6.c(c)), + d -> terminate(Choice6.d(d)), + e -> terminate(Choice6.e(e)), + fRec -> fRec.fmap(Choice6::f)))); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index 1118697bc..8561ea105 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -6,16 +6,20 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple7; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into7.into7; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** @@ -33,7 +37,7 @@ */ public abstract class Choice7 implements CoProduct7>, - Monad>, + MonadRec>, Bifunctor>, Traversable> { @@ -73,7 +77,7 @@ public Choice6 converge(Fn1 Choice7 fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -115,7 +119,7 @@ public Choice7 pure(H h) { @Override public Choice7 zip( Applicative, Choice7> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -138,7 +142,7 @@ public Lazy> lazyZip( */ @Override public Choice7 discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -146,7 +150,7 @@ public Choice7 discardL(Applicative Choice7 discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -158,6 +162,22 @@ public Choice7 flatMap( return match(Choice7::a, Choice7::b, Choice7::c, Choice7::d, Choice7::e, Choice7::f, g -> fn.apply(g).coerce()); } + /** + * {@inheritDoc} + */ + @Override + public Choice7 trampolineM( + Fn1, Choice7>> fn) { + return flatMap(trampoline(g -> fn.apply(g).>>coerce().match( + a -> terminate(a(a)), + b -> terminate(b(b)), + c -> terminate(c(c)), + d -> terminate(d(d)), + e -> terminate(e(e)), + f -> terminate(f(f)), + gRec -> gRec.fmap(Choice7::g)))); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index d0eb8a42b..cc050a90c 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -7,15 +7,19 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple8; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into8.into8; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** @@ -33,7 +37,7 @@ */ public abstract class Choice8 implements CoProduct8>, - Monad>, + MonadRec>, Bifunctor>, Traversable> { @@ -66,7 +70,7 @@ public Choice7 converge( */ @Override public Choice8 fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -108,7 +112,7 @@ public Choice8 pure(I i) { @Override public Choice8 zip( Applicative, Choice8> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -132,7 +136,7 @@ public Lazy> lazyZip( */ @Override public Choice8 discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -140,7 +144,7 @@ public Choice8 discardL(Applicative Choice8 discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -152,6 +156,23 @@ public Choice8 flatMap( return match(Choice8::a, Choice8::b, Choice8::c, Choice8::d, Choice8::e, Choice8::f, Choice8::g, h -> fn.apply(h).coerce()); } + /** + * {@inheritDoc} + */ + @Override + public Choice8 trampolineM( + Fn1, Choice8>> fn) { + return flatMap(trampoline(h -> fn.apply(h).>>coerce().match( + a -> terminate(a(a)), + b -> terminate(b(b)), + c -> terminate(c(c)), + d -> terminate(d(d)), + e -> terminate(e(e)), + f -> terminate(f(f)), + g -> terminate(g(g)), + hRec -> hRec.fmap(Choice8::h)))); + } + /** * {@inheritDoc} */ 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 79ef76c2d..81533a578 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 @@ -5,11 +5,13 @@ import com.jnape.palatable.lambda.adt.product.Product2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn1.Head; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.MonadWriter; import com.jnape.palatable.lambda.traversable.Traversable; @@ -19,6 +21,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * A 2-element tuple product type, implemented as a specialized HList. Supports random access. @@ -35,6 +38,7 @@ public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements Product2<_1, _2>, Map.Entry<_1, _2>, + MonadRec<_2, Tuple2<_1, ?>>, MonadWriter<_1, _2, Tuple2<_1, ?>>, Bifunctor<_1, _2, Tuple2>, Traversable<_2, Tuple2<_1, ?>> { @@ -125,7 +129,7 @@ public Tuple2<_2, _1> invert() { */ @Override public <_2Prime> Tuple2<_1, _2Prime> fmap(Fn1 fn) { - return MonadWriter.super.<_2Prime>fmap(fn).coerce(); + return MonadRec.super.<_2Prime>fmap(fn).coerce(); } /** @@ -169,7 +173,7 @@ public <_2Prime> Tuple2<_1, _2Prime> pure(_2Prime _2Prime) { @Override public <_2Prime> Tuple2<_1, _2Prime> zip( Applicative, Tuple2<_1, ?>> appFn) { - return MonadWriter.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -178,7 +182,7 @@ public <_2Prime> Tuple2<_1, _2Prime> zip( @Override public <_2Prime> Lazy> lazyZip( Lazy, Tuple2<_1, ?>>> lazyAppFn) { - return MonadWriter.super.lazyZip(lazyAppFn).fmap(Monad<_2Prime, Tuple2<_1, ?>>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad<_2Prime, Tuple2<_1, ?>>::coerce); } /** @@ -186,7 +190,7 @@ public <_2Prime> Lazy> lazyZip( */ @Override public <_2Prime> Tuple2<_1, _2Prime> discardL(Applicative<_2Prime, Tuple2<_1, ?>> appB) { - return MonadWriter.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -194,7 +198,7 @@ public <_2Prime> Tuple2<_1, _2Prime> discardL(Applicative<_2Prime, Tuple2<_1, ?> */ @Override public <_2Prime> Tuple2<_1, _2> discardR(Applicative<_2Prime, Tuple2<_1, ?>> appB) { - return MonadWriter.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -205,6 +209,15 @@ public <_2Prime> Tuple2<_1, _2Prime> flatMap(Fn1>coerce()._2()); } + /** + * {@inheritDoc} + */ + @Override + public <_2Prime> Tuple2<_1, _2Prime> trampolineM( + Fn1, Tuple2<_1, ?>>> fn) { + return fmap(trampoline(x -> fn.apply(x).>>coerce()._2())); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 74b82d187..3f2be1e92 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -4,6 +4,7 @@ import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.builtin.fn1.Constantly; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cartesian; @@ -12,12 +13,14 @@ import com.jnape.palatable.lambda.internal.Runtime; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadReader; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.MonadWriter; import java.util.function.Function; import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * A function taking a single argument. This is the core function type that all other function types extend and @@ -28,6 +31,7 @@ */ @FunctionalInterface public interface Fn1 extends + MonadRec>, MonadReader>, MonadWriter>, Cartesian>, @@ -143,7 +147,7 @@ default Fn1 pure(C c) { */ @Override default Fn1 zip(Applicative, Fn1> appFn) { - return MonadReader.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -159,7 +163,15 @@ default Fn1 zip(Fn2 appFn) { */ @Override default Lazy> lazyZip(Lazy, Fn1>> lazyAppFn) { - return MonadReader.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + default Fn1 trampolineM(Fn1, Fn1>> fn) { + return a -> trampoline(b -> fn.apply(b).>>coerce().apply(a), apply(a)); } /** @@ -167,7 +179,7 @@ default Lazy> lazyZip(Lazy Fn1 discardL(Applicative> appB) { - return MonadReader.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -175,7 +187,7 @@ default Fn1 discardL(Applicative> appB) { */ @Override default Fn1 discardR(Applicative> appB) { - return MonadReader.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java index f2b4e9c33..acd35e10f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java @@ -1,21 +1,21 @@ package com.jnape.palatable.lambda.functions.specialized; import com.jnape.palatable.lambda.internal.Runtime; -import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadBase; +import com.jnape.palatable.lambda.monad.MonadRec; /** - * Generalized, portable lifting operation for lifting a {@link Monad} into a {@link MonadBase}. + * Generalized, portable lifting operation for lifting a {@link MonadRec} into a {@link MonadBase}. * * @param the {@link MonadBase} to lift into */ @FunctionalInterface public interface Lift> { - > MonadBase checkedApply(Monad ga) + > MonadBase checkedApply(MonadRec ga) throws Throwable; - default , MBA extends MonadBase> MBA apply(Monad ma) { + default , MBA extends MonadBase> MBA apply(MonadRec ma) { try { @SuppressWarnings("unchecked") MBA MBA = (MBA) checkedApply(ma); return MBA; diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index 0ce465235..a44417bed 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -1,10 +1,12 @@ package com.jnape.palatable.lambda.functor.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; @@ -19,7 +21,7 @@ * @param the right (phantom) parameter type */ public final class Const implements - Monad>, + MonadRec>, Bifunctor>, Traversable> { @@ -48,7 +50,7 @@ public A runConst() { */ @Override public Const fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -65,7 +67,7 @@ public Const pure(C c) { */ @Override public Const zip(Applicative, Const> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -74,7 +76,7 @@ public Const zip(Applicative, Const> @Override public Lazy> lazyZip( Lazy, Const>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -82,7 +84,7 @@ public Lazy> lazyZip( */ @Override public Const discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -90,7 +92,7 @@ public Const discardL(Applicative> appB) { */ @Override public Const discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -102,6 +104,15 @@ public Const flatMap(Fn1>> f return (Const) this; } + /** + * {@inheritDoc} + */ + @Override + @SuppressWarnings("unchecked") + public Const trampolineM(Fn1, Const>> fn) { + return (Const) this; + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java index 103ddb7ff..83ec47711 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Lazy.java @@ -3,9 +3,11 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.LinkedList; @@ -22,7 +24,7 @@ * * @param the value type */ -public abstract class Lazy implements Monad>, Traversable> { +public abstract class Lazy implements MonadRec>, Traversable> { private Lazy() { } @@ -69,7 +71,7 @@ public final Lazy pure(B b) { */ @Override public final Lazy fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -77,7 +79,7 @@ public final Lazy fmap(Fn1 fn) { */ @Override public Lazy zip(Applicative, Lazy> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -85,7 +87,7 @@ public Lazy zip(Applicative, Lazy> appFn) */ @Override public final Lazy discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -93,7 +95,16 @@ public final Lazy discardL(Applicative> appB) { */ @Override public final Lazy discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy trampolineM(Fn1, Lazy>> fn) { + return flatMap(a -> fn.apply(a).>>coerce() + .flatMap(aOrB -> aOrB.match(a_ -> lazy(a_).trampolineM(fn), Lazy::lazy))); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java index 6512abf65..3c8ce7576 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Market.java @@ -4,16 +4,21 @@ import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cocartesian; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.optics.Prism; import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; import static com.jnape.palatable.lambda.functions.Fn1.fn1; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * A profunctor used to extract the isomorphic functions a {@link Prism} is composed of. @@ -24,7 +29,7 @@ * @param the guaranteed output */ public final class Market implements - Monad>, + MonadRec>, Cocartesian> { private final Fn1 bt; @@ -72,6 +77,23 @@ public Market flatMap(Fn1 Market trampolineM( + Fn1, Market>> fn) { + Fn1 bu = Fn1.fn1(bt).trampolineM(t -> fn1(fn.apply(t).>>coerce().bt)); + Fn1> sua = Fn1.>fn1(sta) + .flatMap(tOrA -> fn1(s -> tOrA.match( + trampoline(t -> fn.apply(t).>>coerce() + .sta.apply(s) + .match(tOrU -> tOrU.match(RecursiveResult::recurse, u -> terminate(left(u))), + a -> terminate(right(a)))), + Either::right))); + return new Market<>(bu, sua); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java index 8c1e84a41..5caa98d18 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/State.java @@ -3,18 +3,23 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadReader; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.MonadWriter; import com.jnape.palatable.lambda.monad.transformer.builtin.StateT; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn1.fn1; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.stateT; /** @@ -26,7 +31,10 @@ * @param the state type * @param the result type */ -public final class State implements MonadReader>, MonadWriter> { +public final class State implements + MonadRec>, + MonadReader>, + MonadWriter> { private final StateT, A> stateFn; @@ -130,7 +138,7 @@ public State pure(B b) { */ @Override public State fmap(Fn1 fn) { - return MonadReader.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -138,7 +146,7 @@ public State fmap(Fn1 fn) { */ @Override public State zip(Applicative, State> appFn) { - return MonadReader.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -147,7 +155,7 @@ public State zip(Applicative, State> @Override public Lazy> lazyZip( Lazy, State>> lazyAppFn) { - return MonadReader.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -155,7 +163,7 @@ public Lazy> lazyZip( */ @Override public State discardR(Applicative> appB) { - return MonadReader.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -163,7 +171,17 @@ public State discardR(Applicative> appB) { */ @Override public State discardL(Applicative> appB) { - return MonadReader.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public State trampolineM(Fn1, State>> fn) { + return state(fn1(this::run).fmap(trampoline(into((a, s) -> fn.apply(a) + .>>coerce().run(s) + .into((aOrB, s_) -> aOrB.biMap(a_ -> tuple(a_, s_), b -> tuple(b, s_))))))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java index 24987beb8..4231f2959 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Tagged.java @@ -3,15 +3,18 @@ import com.jnape.palatable.lambda.adt.choice.Choice2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn1.Downcast; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cocartesian; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * Like {@link Const}, but the phantom parameter is in the contravariant position, and the value is in covariant @@ -21,9 +24,8 @@ * @param the value type */ public final class Tagged implements - Monad>, - Traversable>, - Cocartesian> { + MonadRec>, + Traversable>, Cocartesian> { private final B b; @@ -48,6 +50,15 @@ public Tagged flatMap(Fn1>> return f.apply(b).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public Tagged trampolineM(Fn1, Tagged>> fn) { + return new Tagged<>(trampoline(b -> fn.apply(b).>>coerce().unTagged(), + unTagged())); + } + /** * {@inheritDoc} */ @@ -61,7 +72,7 @@ public Tagged pure(C c) { */ @Override public Tagged fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -69,7 +80,7 @@ public Tagged fmap(Fn1 fn) { */ @Override public Tagged zip(Applicative, Tagged> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -77,7 +88,7 @@ public Tagged zip(Applicative, Tagged Tagged discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -85,7 +96,7 @@ public Tagged discardL(Applicative> appB) { */ @Override public Tagged discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/io/IO.java b/src/main/java/com/jnape/palatable/lambda/io/IO.java index fe24296f2..6af4dc1b1 100644 --- a/src/main/java/com/jnape/palatable/lambda/io/IO.java +++ b/src/main/java/com/jnape/palatable/lambda/io/IO.java @@ -7,12 +7,14 @@ import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.LazyRec; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadError; +import com.jnape.palatable.lambda.monad.MonadRec; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -38,7 +40,7 @@ * * @param the result type */ -public abstract class IO implements MonadError> { +public abstract class IO implements MonadRec>, MonadError> { private IO() { } @@ -173,6 +175,16 @@ public final IO flatMap(Fn1>> f) { return new Compose<>(this, composition); } + /** + * {@inheritDoc} + */ + @Override + public IO trampolineM(Fn1, IO>> fn) { + return flatMap(a -> fn.apply(a).>>coerce().flatMap(aOrB -> aOrB.match( + a_ -> io(a_).trampolineM(fn), + IO::io))); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadBase.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadBase.java index 5644b0a30..36798e8eb 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/MonadBase.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadBase.java @@ -1,22 +1,22 @@ package com.jnape.palatable.lambda.monad; /** - * A type into which a {@link Monad} is embedded whilst internally preserving the {@link Monad} structure. + * A type into which a {@link MonadRec} is embedded whilst internally preserving the {@link MonadRec} structure. * - * @param the {@link Monad} embedded in this {@link MonadBase} + * @param the {@link MonadRec} embedded in this {@link MonadBase} * @param the carrier type * @param the witness */ @SuppressWarnings("unused") -public interface MonadBase, A, MB extends MonadBase> { +public interface MonadBase, A, MB extends MonadBase> { /** - * Lift a new argument {@link Monad} into this {@link MonadBase}. + * Lift a new argument {@link MonadRec} into this {@link MonadBase}. * - * @param nc the argument {@link Monad} - * @param the {@link Monad} carrier type - * @param the argument {@link Monad} witness + * @param nc the argument {@link MonadRec} + * @param the {@link MonadRec} carrier type + * @param the argument {@link MonadRec} witness * @return the new {@link MonadBase} */ - > MonadBase lift(Monad nc); + > MonadBase lift(MonadRec nc); } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java index 2d88f9ba3..bcecdcad8 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadError.java @@ -1,6 +1,8 @@ package com.jnape.palatable.lambda.monad; import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Try; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -15,6 +17,10 @@ * @param the error type * @param the {@link Monad} witness * @param the carrier + * @see IO + * @see Either + * @see Try + * @see Maybe */ public interface MonadError> extends Monad { diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java index fd887da18..8d4492422 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java @@ -1,41 +1,90 @@ package com.jnape.palatable.lambda.monad; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.transformer.MonadT; +import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT; +/** + * A class of {@link Monad monads} that offer a stack-safe interface for performing arbitrarily many + * {@link Monad#flatMap(Fn1) flatmap-like} operations via {@link MonadRec#trampolineM(Fn1)}. + * + * @param the carrier type + * @param the {@link MonadRec witness} + */ public interface MonadRec> extends Monad { + /** + * Given some operation yielding a {@link RecursiveResult} inside this {@link MonadRec}, internally trampoline the + * operation until it yields a {@link RecursiveResult#terminate(Object) termination} instruction. + *

+ * Stack-safety depends on implementations guaranteeing that the growth of the call stack is a constant factor + * independent of the number of invocations of the operation. For various examples of how this can be achieved in + * stereotypical circumstances, see the referenced types. + * + * @param fn the function to internally trampoline + * @param the ultimate resulting carrier type + * @return the trampolined {@link MonadRec} + * @see Identity#trampolineM(Fn1) for a basic implementation + * @see Maybe#trampolineM(Fn1) for a {@link CoProduct2 coproduct} implementation + * @see Lazy#trampolineM(Fn1) for an implementation leveraging an already stack-safe {@link Monad#flatMap(Fn1)} + * @see MaybeT#trampolineM(Fn1) for a {@link MonadT monad transformer} implementation + */ MonadRec trampolineM(Fn1, M>> fn); + /** + * {@inheritDoc} + */ @Override MonadRec flatMap(Fn1> f); + /** + * {@inheritDoc} + */ @Override MonadRec pure(B b); + /** + * {@inheritDoc} + */ @Override default MonadRec fmap(Fn1 fn) { return Monad.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override default MonadRec zip(Applicative, M> appFn) { return Monad.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override default Lazy> lazyZip( Lazy, M>> lazyAppFn) { return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); } + /** + * {@inheritDoc} + */ @Override default MonadRec discardL(Applicative appB) { return Monad.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override default MonadRec discardR(Applicative appB) { return Monad.super.discardR(appB).coerce(); diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java index 8a68783d5..71ed2b24b 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadBase; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.builtin.EitherT; import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT; import com.jnape.palatable.lambda.monad.transformer.builtin.ReaderT; @@ -39,14 +40,14 @@ * @see EitherT * @see ReaderT */ -public interface MonadT, A, MT extends MonadT, T extends MonadT> extends - MonadBase, - Monad { +public interface MonadT, A, MT extends MonadT, T extends MonadT> + extends MonadBase, Monad, MonadRec { /** * {@inheritDoc} */ - > MonadT lift(Monad mb); + @Override + > MonadT lift(MonadRec mb); /** * {@inheritDoc} @@ -65,7 +66,7 @@ public interface MonadT, A, MT extends MonadT */ @Override default MonadT fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -73,7 +74,7 @@ default MonadT fmap(Fn1 fn) { */ @Override default MonadT zip(Applicative, MT> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -82,7 +83,7 @@ default MonadT zip(Applicative, MT> @Override default Lazy> lazyZip( Lazy, MT>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); } /** @@ -90,7 +91,7 @@ default Lazy> lazyZip( */ @Override default MonadT discardL(Applicative appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -98,6 +99,6 @@ default MonadT discardL(Applicative appB) { */ @Override default MonadT discardR(Applicative appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java index 2fc30f672..340edd066 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; @@ -9,27 +10,29 @@ import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.MonadT; import java.util.Objects; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; /** * A {@link MonadT monad transformer} for {@link Either}. * - * @param the outer {@link Monad} + * @param the outer {@link Monad stack-safe monad} * @param the left type * @param the right type */ -public final class EitherT, L, R> implements +public final class EitherT, L, R> implements Bifunctor>, MonadT, EitherT> { - private final Monad, M> melr; + private final MonadRec, M> melr; - private EitherT(Monad, M> melr) { + private EitherT(MonadRec, M> melr) { this.melr = melr; } @@ -39,7 +42,7 @@ private EitherT(Monad, M> melr) { * @param the witnessed target type * @return the embedded {@link Monad} */ - public , M>> MELR runEitherT() { + public , M>> MELR runEitherT() { return melr.coerce(); } @@ -47,7 +50,7 @@ public , M>> MELR runEitherT() { * {@inheritDoc} */ @Override - public > EitherT lift(Monad mb) { + public > EitherT lift(MonadRec mb) { return EitherT.liftEitherT().apply(mb); } @@ -94,7 +97,7 @@ public Lazy> lazyZip( return new Compose<>(melr) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( maybeT.>>coerce() - .>, M>>runEitherT()))) + .>, M>>runEitherT()))) .fmap(compose -> eitherT(compose.getCompose())); } @@ -114,6 +117,20 @@ public EitherT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public EitherT trampolineM( + Fn1, EitherT>> fn) { + return eitherT(runEitherT().trampolineM(lOrR -> lOrR + .match(l -> melr.pure(terminate(left(l))), + r -> fn.apply(r).>>coerce() + .runEitherT() + .fmap(lOrRR -> lOrRR.match(l -> terminate(left(l)), + rr -> rr.biMap(Either::right, Either::right)))))); + } + /** * {@inheritDoc} */ @@ -164,7 +181,7 @@ public String toString() { * @param the right type * @return the {@link EitherT} */ - public static , L, R> EitherT eitherT(Monad, M> melr) { + public static , L, R> EitherT eitherT(MonadRec, M> melr) { return new EitherT<>(melr); } @@ -176,11 +193,11 @@ public static , L, R> EitherT eitherT(Monad the left type * @return the {@link Pure} instance */ - public static , L> Pure> pureEitherT(Pure pureM) { + public static , L> Pure> pureEitherT(Pure pureM) { return new Pure>() { @Override public EitherT checkedApply(R r) throws Throwable { - return eitherT(pureM.>apply(r).fmap(Either::right)); + return eitherT(pureM.>apply(r).fmap(Either::right)); } }; } @@ -194,7 +211,7 @@ public EitherT checkedApply(R r) throws Throwable { public static Lift> liftEitherT() { return new Lift>() { @Override - public > EitherT checkedApply(Monad ga) { + public > EitherT checkedApply(MonadRec ga) { return eitherT(ga.fmap(Either::right)); } }; diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java index 092a71fb2..42f6f326c 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; @@ -8,6 +9,7 @@ import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.MonadT; import java.util.Objects; @@ -15,14 +17,15 @@ /** * A {@link MonadT monad transformer} for {@link Identity}. * - * @param the outer {@link Monad} + * @param the outer {@link Monad stack-safe monad} * @param the carrier type */ -public final class IdentityT, A> implements MonadT, IdentityT> { +public final class IdentityT, A> implements + MonadT, IdentityT> { - private final Monad, M> mia; + private final MonadRec, M> mia; - private IdentityT(Monad, M> mia) { + private IdentityT(MonadRec, M> mia) { this.mia = mia; } @@ -32,7 +35,7 @@ private IdentityT(Monad, M> mia) { * @param the witnessed target type * @return the embedded {@link Monad} */ - public , M>> MIA runIdentityT() { + public , M>> MIA runIdentityT() { return mia.coerce(); } @@ -40,7 +43,7 @@ public , M>> MIA runIdentityT() { * {@inheritDoc} */ @Override - public > IdentityT lift(Monad mb) { + public > IdentityT lift(MonadRec mb) { return liftIdentityT().apply(mb); } @@ -49,7 +52,23 @@ public > IdentityT lift(Monad mb) { */ @Override public IdentityT flatMap(Fn1>> f) { - return identityT(mia.flatMap(identityA -> f.apply(identityA.runIdentity()).>coerce().runIdentityT())); + return identityT(mia.flatMap(identityA -> f.apply(identityA.runIdentity()) + .>coerce() + .runIdentityT())); + } + + /** + * {@inheritDoc} + */ + @Override + public IdentityT trampolineM( + Fn1, IdentityT>> fn) { + return identityT(runIdentityT().fmap(Identity::runIdentity) + .trampolineM(a -> fn.apply(a) + .>>coerce() + .runIdentityT() + .fmap(Identity::runIdentity)) + .fmap(Identity::new)); } /** @@ -85,7 +104,7 @@ public Lazy> lazyZip( return new Compose<>(mia) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( maybeT.>>coerce() - .>, M>>runIdentityT()))) + .>, M>>runIdentityT()))) .fmap(compose -> identityT(compose.getCompose())); } @@ -129,7 +148,7 @@ public String toString() { * @param the carrier type * @return the new {@link IdentityT}. */ - public static , A> IdentityT identityT(Monad, M> mia) { + public static , A> IdentityT identityT(MonadRec, M> mia) { return new IdentityT<>(mia); } @@ -140,11 +159,11 @@ public static , A> IdentityT identityT(Monad the argument {@link Monad} witness * @return the {@link Pure} instance */ - public static > Pure> pureIdentityT(Pure pureM) { + public static > Pure> pureIdentityT(Pure pureM) { return new Pure>() { @Override public IdentityT checkedApply(A a) { - return identityT(pureM.>apply(a).fmap(Identity::new)); + return identityT(pureM.>apply(a).fmap(Identity::new)); } }; } @@ -157,7 +176,7 @@ public IdentityT checkedApply(A a) { public static Lift> liftIdentityT() { return new Lift>() { @Override - public > IdentityT checkedApply(Monad ga) { + public > IdentityT checkedApply(MonadRec ga) { return identityT(ga.fmap(Identity::new)); } }; diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java index 52c531c75..5af654230 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java @@ -1,12 +1,14 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.MonadT; import java.util.Objects; @@ -14,16 +16,18 @@ import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** - * A {@link MonadT monad transformer} for {@link Lazy}. Note that {@link LazyT#flatMap(Fn1)} must force its value. + * A {@link MonadT monad transformer} for {@link Lazy}. Note that both {@link LazyT#flatMap(Fn1)} and + * {@link LazyT#trampolineM} must force its value. * - * @param the outer {@link Monad} + * @param the outer {@link Monad stack-safe monad} * @param the carrier type */ -public final class LazyT, A> implements MonadT, LazyT> { +public final class LazyT, A> implements + MonadT, LazyT> { - private final Monad, M> mla; + private final MonadRec, M> mla; - private LazyT(Monad, M> mla) { + private LazyT(MonadRec, M> mla) { this.mla = mla; } @@ -33,7 +37,7 @@ private LazyT(Monad, M> mla) { * @param the witnessed target type * @return the embedded {@link Monad} */ - public , M>> MLA runLazyT() { + public , M>> MLA runLazyT() { return mla.coerce(); } @@ -41,7 +45,7 @@ public , M>> MLA runLazyT() { * {@inheritDoc} */ @Override - public > LazyT lift(Monad mb) { + public > LazyT lift(MonadRec mb) { return liftLazyT().apply(mb); } @@ -53,6 +57,16 @@ public LazyT flatMap(Fn1>> f return new LazyT<>(mla.flatMap(lazyA -> f.apply(lazyA.value()).>coerce().runLazyT())); } + /** + * {@inheritDoc} + */ + @Override + public LazyT trampolineM(Fn1, LazyT>> fn) { + return lazyT(runLazyT().trampolineM(lazyA -> fn.apply(lazyA.value()) + .>>coerce() + .runLazyT().fmap(lAOrB -> lAOrB.value().biMap(Lazy::lazy, Lazy::lazy)))); + } + /** * {@inheritDoc} */ @@ -86,7 +100,7 @@ public Lazy> lazyZip( return new Compose<>(mla) .lazyZip(lazyAppFn.fmap(lazyT -> new Compose<>( lazyT.>>coerce() - .>, M>>runLazyT()))) + .>, M>>runLazyT()))) .fmap(compose -> lazyT(compose.getCompose())); } @@ -130,7 +144,7 @@ public String toString() { * @param the carrier type * @return the new {@link LazyT} */ - public static , A> LazyT lazyT(Monad, M> mla) { + public static , A> LazyT lazyT(MonadRec, M> mla) { return new LazyT<>(mla); } @@ -141,11 +155,11 @@ public static , A> LazyT lazyT(Monad, M> mla * @param the argument {@link Monad} witness * @return the {@link Pure} instance */ - public static > Pure> pureLazyT(Pure pureM) { + public static > Pure> pureLazyT(Pure pureM) { return new Pure>() { @Override public LazyT checkedApply(A a) { - return lazyT(pureM.>apply(a).fmap(Lazy::lazy)); + return lazyT(pureM.>apply(a).fmap(Lazy::lazy)); } }; } @@ -158,7 +172,7 @@ public LazyT checkedApply(A a) { public static Lift> liftLazyT() { return new Lift>() { @Override - public > LazyT checkedApply(Monad ga) { + public > LazyT checkedApply(MonadRec ga) { return lazyT(ga.fmap(Lazy::lazy)); } }; diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index b105175ae..3a6cad1f8 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -2,12 +2,14 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.MonadT; import java.util.Objects; @@ -15,18 +17,20 @@ import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; /** * A {@link MonadT monad transformer} for {@link Maybe}. * - * @param the outer {@link Monad} + * @param the outer {@link Monad stack-safe monad} * @param the carrier type */ -public final class MaybeT, A> implements MonadT, MaybeT> { +public final class MaybeT, A> implements + MonadT, MaybeT> { - private final Monad, M> mma; + private final MonadRec, M> mma; - private MaybeT(Monad, M> mma) { + private MaybeT(MonadRec, M> mma) { this.mma = mma; } @@ -36,7 +40,7 @@ private MaybeT(Monad, M> mma) { * @param the witnessed target type * @return the embedded {@link Monad} */ - public , M>> MMA runMaybeT() { + public , M>> MMA runMaybeT() { return mma.coerce(); } @@ -44,7 +48,7 @@ public , M>> MMA runMaybeT() { * {@inheritDoc} */ @Override - public > MaybeT lift(Monad mb) { + public > MaybeT lift(MonadRec mb) { return liftMaybeT().apply(mb); } @@ -81,7 +85,7 @@ public Lazy> lazyZip( return new Compose<>(mma) .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( maybeT.>>coerce() - .>, M>>runMaybeT()))) + .>, M>>runMaybeT()))) .fmap(compose -> maybeT(compose.getCompose())); } @@ -95,6 +99,20 @@ public MaybeT flatMap(Fn1>> a -> f.apply(a).>coerce().runMaybeT()))); } + /** + * {@inheritDoc} + */ + @Override + public MaybeT trampolineM(Fn1, MaybeT>> fn) { + return maybeT(runMaybeT().trampolineM(maybeA -> maybeA.match( + constantly(runMaybeT().pure(terminate(nothing()))), + a -> fn.apply(a).>>coerce() + .runMaybeT() + .fmap(maybeRec -> maybeRec.match( + constantly(terminate(nothing())), + aOrB -> aOrB.biMap(Maybe::just, Maybe::just)))))); + } + /** * {@inheritDoc} */ @@ -137,7 +155,7 @@ public String toString() { * @param the carrier type * @return the {@link MaybeT} */ - public static , A> MaybeT maybeT(Monad, M> mma) { + public static , A> MaybeT maybeT(MonadRec, M> mma) { return new MaybeT<>(mma); } @@ -148,11 +166,11 @@ public static , A> MaybeT maybeT(Monad, M> * @param the argument {@link Monad} witness * @return the {@link Pure} instance */ - public static > Pure> pureMaybeT(Pure pureM) { + public static > Pure> pureMaybeT(Pure pureM) { return new Pure>() { @Override public MaybeT checkedApply(A a) { - return maybeT(pureM.>apply(a).fmap(Maybe::just)); + return maybeT(pureM.>apply(a).fmap(Maybe::just)); } }; } @@ -166,7 +184,7 @@ public MaybeT checkedApply(A a) { public static Lift> liftMaybeT() { return new Lift>() { @Override - public > MaybeT checkedApply(Monad ga) { + public > MaybeT checkedApply(MonadRec ga) { return maybeT(ga.fmap(Maybe::just)); } }; diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index 3e496e2c9..e2624b381 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; @@ -9,6 +10,7 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadReader; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.MonadT; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; @@ -17,20 +19,20 @@ /** * A {@link MonadT monad transformer} for any {@link Fn1 function} from some type R to some - * {@link Monad monadic} embedding {@link Monad}<A, M>. + * {@link MonadRec monadic} embedding {@link MonadRec}<A, M>. * * @param the input type - * @param the returned {@link Monad} + * @param the returned {@link MonadRec} * @param the embedded output type */ -public final class ReaderT, A> implements +public final class ReaderT, A> implements MonadReader>, Cartesian>, MonadT, ReaderT> { - private final Fn1> f; + private final Fn1> f; - private ReaderT(Fn1> f) { + private ReaderT(Fn1> f) { this.f = f; } @@ -39,23 +41,17 @@ private ReaderT(Fn1> f) { * * @param r the input * @param the witnessed target type - * @return the embedded {@link Monad} + * @return the embedded {@link MonadRec} */ - public > MA runReaderT(R r) { + public > MA runReaderT(R r) { return f.apply(r).coerce(); } /** * Map the current {@link Monad monadic} embedding to a new one in a potentially different {@link Monad}. - * - * @param fn the mapping function - * @param the inference target of the current {@link Monad monadic} embedding - * @param the new {@link Monad} to embed the result in - * @param the new embedded result - * @return the mapped {@link ReaderT} - */ - public , N extends Monad, B> ReaderT mapReaderT( - Fn1> fn) { + */ + public , N extends MonadRec, B> ReaderT mapReaderT( + Fn1> fn) { return readerT(r -> fn.apply(runReaderT(r).coerce())); } @@ -71,7 +67,7 @@ public ReaderT local(Fn1 fn) { * {@inheritDoc} */ @Override - public > ReaderT lift(Monad mb) { + public > ReaderT lift(MonadRec mb) { return ReaderT.liftReaderT().apply(mb); } @@ -83,6 +79,16 @@ public ReaderT flatMap(Fn1 runReaderT(r).flatMap(a -> f.apply(a).>coerce().runReaderT(r))); } + /** + * {@inheritDoc} + */ + @Override + public ReaderT trampolineM( + Fn1, ReaderT>> fn) { + return readerT(r -> runReaderT(r).trampolineM(a -> fn.apply(a).>>coerce() + .runReaderT(r))); + } + /** * {@inheritDoc} */ @@ -189,7 +195,7 @@ public ReaderT> carry() { * @param the embedded output type * @return the {@link ReaderT} */ - static , A> ReaderT readerT(Fn1> fn) { + static , A> ReaderT readerT(Fn1> fn) { return new ReaderT<>(fn); } @@ -201,7 +207,7 @@ static , A> ReaderT readerT(Fn1 the argument {@link Monad} witness * @return the {@link Pure} instance */ - public static > Pure> pureReaderT(Pure pureM) { + public static > Pure> pureReaderT(Pure pureM) { return new Pure>() { @Override public ReaderT checkedApply(A a) { @@ -219,7 +225,7 @@ public ReaderT checkedApply(A a) { public static Lift> liftReaderT() { return new Lift>() { @Override - public > ReaderT checkedApply(Monad ga) { + public > ReaderT checkedApply(MonadRec ga) { return readerT(constantly(ga)); } }; diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java index b48db7887..907d71d51 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; @@ -10,6 +11,7 @@ import com.jnape.palatable.lambda.functor.builtin.State; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadReader; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.MonadWriter; import com.jnape.palatable.lambda.monad.transformer.MonadT; @@ -28,14 +30,14 @@ * @param the result type * @see State */ -public final class StateT, A> implements +public final class StateT, A> implements MonadT, StateT>, MonadReader>, MonadWriter> { - private final Fn1, M>> stateFn; + private final Fn1, M>> stateFn; - private StateT(Fn1, M>> stateFn) { + private StateT(Fn1, M>> stateFn) { this.stateFn = stateFn; } @@ -47,7 +49,7 @@ private StateT(Fn1, M>> stateFn) { * @param the inferred {@link Monad} result * @return a {@link Tuple2} of the result and the final state. */ - public , M>> MAS runStateT(S s) { + public , M>> MAS runStateT(S s) { return stateFn.apply(s).coerce(); } @@ -81,8 +83,8 @@ public > MS execT(S s) { * @param the new state type * @return the mapped {@link StateT} */ - public , B> StateT mapStateT( - Fn1, M>, ? extends Monad, N>> fn) { + public , B> StateT mapStateT( + Fn1, M>, ? extends MonadRec, N>> fn) { return stateT(s -> fn.apply(runStateT(s))); } @@ -93,7 +95,7 @@ public , B> StateT mapStateT( * @param fn the state-mapping function * @return the mapped {@link StateT} */ - public StateT withStateT(Fn1> fn) { + public StateT withStateT(Fn1> fn) { return modify(fn).flatMap(constantly(this)); } @@ -186,10 +188,23 @@ public StateT discardR(Applicative> appB) { * {@inheritDoc} */ @Override - public > StateT lift(Monad mb) { + public > StateT lift(MonadRec mb) { return stateT(s -> mb.fmap(b -> tuple(b, s))); } + /** + * {@inheritDoc} + */ + @Override + public StateT trampolineM( + Fn1, StateT>> fn) { + return StateT.stateT((Fn1., M>>fn1(this::runStateT)) + .fmap(m -> m.trampolineM(into((a, s) -> fn.apply(a) + .>>coerce().runStateT(s) + .fmap(into((aOrB, s_) -> aOrB.biMap(a_ -> tuple(a_, s_), + b -> tuple(b, s_)))))))); + } + /** * Given a {@link Pure pure} construction of some {@link Monad}, produce a {@link StateT} that equates its output * with its state. @@ -200,8 +215,8 @@ public > StateT lift(Monad mb) { * @return the {@link StateT} */ @SuppressWarnings("RedundantTypeArguments") - public static > StateT get(Pure pureM) { - return gets(pureM::>apply); + public static > StateT get(Pure pureM) { + return gets(pureM::>apply); } /** @@ -214,7 +229,7 @@ public static > StateT get(Pure pureM) { * @param the value type * @return the {@link StateT} */ - public static , A> StateT gets(Fn1> fn) { + public static , A> StateT gets(Fn1> fn) { return stateT(s -> fn.apply(s).fmap(a -> tuple(a, s))); } @@ -226,24 +241,25 @@ public static , A> StateT gets(Fn1 the {@link Monad} embedding * @return the {@link StateT} */ - public static > StateT modify(Fn1> updateFn) { + public static > StateT modify( + Fn1> updateFn) { return stateT(s -> updateFn.apply(s).fmap(tupler(UNIT))); } /** - * Lift a {@link Monad monadic state} into {@link StateT}. + * Lift a {@link MonadRec monadic state} into {@link StateT}. * * @param ms the state * @param the state type - * @param the {@link Monad} embedding + * @param the {@link MonadRec} embedding * @return the {@link StateT} */ - public static > StateT put(Monad ms) { + public static > StateT put(MonadRec ms) { return modify(constantly(ms)); } /** - * Lift a {@link Monad monadic value} into {@link StateT}. + * Lift a {@link MonadRec monadic value} into {@link StateT}. * * @param ma the value * @param the state type @@ -251,7 +267,7 @@ public static > StateT put(Monad ms) * @param the result type * @return the {@link StateT} */ - public static , A> StateT stateT(Monad ma) { + public static , A> StateT stateT(MonadRec ma) { return gets(constantly(ma)); } @@ -264,8 +280,8 @@ public static , A> StateT stateT(Monad m * @param the result type * @return the {@link StateT} */ - public static , A> StateT stateT( - Fn1, M>> stateFn) { + public static , A> StateT stateT( + Fn1, M>> stateFn) { return new StateT<>(stateFn); } @@ -277,11 +293,11 @@ public static , A> StateT stateT( * @param the argument {@link Monad} witness * @return the {@link Pure} instance */ - public static > Pure> pureStateT(Pure pureM) { + public static > Pure> pureStateT(Pure pureM) { return new Pure>() { @Override public StateT checkedApply(A a) throws Throwable { - return stateT(pureM.>apply(a)); + return stateT(pureM.>apply(a)); } }; } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java index d661e1f69..da80ad984 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java @@ -3,11 +3,13 @@ import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.MonadWriter; import com.jnape.palatable.lambda.monad.transformer.MonadT; import com.jnape.palatable.lambda.monoid.Monoid; @@ -27,13 +29,13 @@ * @param the {@link Monad monadic embedding} * @param the result type */ -public final class WriterT, A> implements +public final class WriterT, A> implements MonadWriter>, MonadT, WriterT> { - private final Fn1, ? extends Monad, M>> writerFn; + private final Fn1, ? extends MonadRec, M>> writerFn; - private WriterT(Fn1, ? extends Monad, M>> writerFn) { + private WriterT(Fn1, ? extends MonadRec, M>> writerFn) { this.writerFn = writerFn; } @@ -46,7 +48,7 @@ private WriterT(Fn1, ? extends Monad, M>> writerF * @param the inferred {@link Monad} result * @return the accumulation with the result */ - public , M>> MAW runWriterT(Monoid monoid) { + public , M>> MAW runWriterT(Monoid monoid) { return writerFn.apply(monoid).coerce(); } @@ -70,10 +72,22 @@ public WriterT censor(Fn1 fn) { * {@inheritDoc} */ @Override - public > WriterT lift(Monad mb) { + public > WriterT lift(MonadRec mb) { return WriterT.liftWriterT().apply(mb); } + /** + * {@inheritDoc} + */ + @Override + public WriterT trampolineM( + Fn1, WriterT>> fn) { + return new WriterT<>(monoid -> runWriterT(monoid).trampolineM(into((a, w) -> fn.apply(a) + .>>coerce() + .runWriterT(monoid).fmap(t -> t.fmap(monoid.apply(w))) + .fmap(into((aOrB, w_) -> aOrB.biMap(a_ -> tuple(a_, w_), b -> tuple(b, w_))))))); + } + /** * {@inheritDoc} */ @@ -143,7 +157,7 @@ public WriterT discardR(Applicative> appB) { * @param the {@link Monad} type * @return the {@link WriterT} */ - public static > WriterT tell(Monad mw) { + public static > WriterT tell(MonadRec mw) { return writerT(mw.fmap(tupler(UNIT))); } @@ -156,7 +170,7 @@ public static > WriterT tell(Monad mw * @param the value type * @return the {@link WriterT} */ - public static , A> WriterT listen(Monad ma) { + public static , A> WriterT listen(MonadRec ma) { return new WriterT<>(monoid -> ma.fmap(a -> tuple(a, monoid.identity()))); } @@ -169,7 +183,7 @@ public static , A> WriterT listen(Monad * @param the value type * @return the {@link WriterT} */ - public static , A> WriterT writerT(Monad, M> mwa) { + public static , A> WriterT writerT(MonadRec, M> mwa) { return new WriterT<>(constantly(mwa)); } @@ -181,11 +195,11 @@ public static , A> WriterT writerT(Monad the argument {@link Monad} witness * @return the {@link Pure} instance */ - public static > Pure> pureWriterT(Pure pureM) { + public static > Pure> pureWriterT(Pure pureM) { return new Pure>() { @Override public WriterT checkedApply(A a) throws Throwable { - return listen(pureM.>apply(a)); + return listen(pureM.>apply(a)); } }; } diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java index 07652a32a..04c21ccfb 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Iso.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Iso.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Functor; @@ -10,6 +11,7 @@ import com.jnape.palatable.lambda.functor.builtin.Exchange; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.optics.functions.Over; import com.jnape.palatable.lambda.optics.functions.Set; import com.jnape.palatable.lambda.optics.functions.View; @@ -56,7 +58,7 @@ @FunctionalInterface public interface Iso extends Optic, Functor, S, T, A, B>, - Monad>, + MonadRec>, Profunctor> { /** @@ -97,7 +99,7 @@ default Iso mirror() { */ @Override default Iso fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -113,7 +115,7 @@ default Iso pure(U u) { */ @Override default Iso zip(Applicative, Iso> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -121,7 +123,7 @@ default Iso zip(Applicative, Iso Iso discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -129,7 +131,7 @@ default Iso discardL(Applicative> appB) { */ @Override default Iso discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -148,6 +150,18 @@ default Iso flatMap(Fn1 Iso trampolineM( + Fn1, Iso>> fn) { + return unIso().into((sa, bt) -> iso( + sa, + Fn1.fn1(bt).trampolineM(t -> fn1(fn.apply(t)., A, B>>coerce() + .unIso()._2())))); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java index 120be9964..f2b0c23d6 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Lens.java @@ -4,14 +4,18 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.builtin.fn2.Both; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cartesian; import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.Profunctor; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn1.fn1; +import static com.jnape.palatable.lambda.functions.Fn2.curried; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.optics.Iso.iso; import static com.jnape.palatable.lambda.optics.Lens.Simple.adapt; @@ -143,7 +147,7 @@ @FunctionalInterface public interface Lens extends Optic, Functor, S, T, A, B>, - Monad>, + MonadRec>, Profunctor> { /** @@ -151,7 +155,7 @@ public interface Lens extends */ @Override default Lens fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -167,7 +171,7 @@ default Lens pure(U u) { */ @Override default Lens zip(Applicative, Lens> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -175,7 +179,7 @@ default Lens zip(Applicative, Lens Lens discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -183,7 +187,7 @@ default Lens discardL(Applicative> appB) { */ @Override default Lens discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -195,6 +199,18 @@ default Lens flatMap(Fn1 set(f.apply(set(this, b, s)).>coerce(), b, s)); } + /** + * {@inheritDoc} + */ + @Override + default Lens trampolineM( + Fn1, Lens>> fn) { + return lens(view(this), + curried(set(this).flip().flatMap(bt -> fn1(s -> bt + .trampolineM(t -> set(fn.apply(t)., A, B>>coerce()) + .flip().apply(s)))))); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java index 3bf6b72b4..698860cbf 100644 --- a/src/main/java/com/jnape/palatable/lambda/optics/Prism.java +++ b/src/main/java/com/jnape/palatable/lambda/optics/Prism.java @@ -6,6 +6,7 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Cocartesian; @@ -15,6 +16,7 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.functor.builtin.Market; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.optics.functions.Matching; import com.jnape.palatable.lambda.optics.functions.Pre; import com.jnape.palatable.lambda.optics.functions.Re; @@ -57,7 +59,7 @@ @FunctionalInterface public interface Prism extends ProtoOptic, S, T, A, B>, - Monad>, + MonadRec>, Profunctor> { /** @@ -156,7 +158,7 @@ default Prism flatMap(Fn1 Prism fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -164,7 +166,7 @@ default Prism fmap(Fn1 fn) { */ @Override default Prism zip(Applicative, Prism> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -173,7 +175,7 @@ default Prism zip(Applicative, Prism @Override default Lazy> lazyZip( Lazy, Prism>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -181,7 +183,7 @@ default Lazy> lazyZip( */ @Override default Prism discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -189,7 +191,20 @@ default Prism discardL(Applicative> appB) { */ @Override default Prism discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + default Prism trampolineM( + Fn1, Prism>> fn) { + Market absu = unPrism().into(Market::new) + .trampolineM(t -> fn.apply(t)., A, B>>coerce() + .unPrism() + .into(Market>::new)); + return prism(absu.sta(), absu.bt()); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index a3fca2cbf..1d4ed3b0f 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -10,6 +10,7 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import java.io.IOException; @@ -47,7 +48,7 @@ public class TryTest { @Rule public ExpectedException thrown = ExpectedException.none(); - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class, MonadRecLaws.class}) public Subjects> testSubject() { return subjects(failure(new IllegalStateException()), success(1)); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java index c93928ada..1d761f0ee 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice6Test.java @@ -12,6 +12,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.choice.Choice6.a; @@ -44,7 +45,13 @@ public void setUp() { f = f(5L); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + BifunctorLaws.class, + TraversableLaws.class, + MonadRecLaws.class}) public Subjects> testSubjects() { return subjects(a("foo"), b(1), c(true), d('a'), e(2d), f(5L)); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java index 5d1eb86a1..fd2dc7637 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice7Test.java @@ -12,6 +12,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.choice.Choice7.a; @@ -47,7 +48,13 @@ public void setUp() { g = g(6F); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + BifunctorLaws.class, + TraversableLaws.class, + MonadRecLaws.class}) public Subjects> testSubjects() { return subjects(a("foo"), b(1), c(true), d('a'), e(2d), f(5L), g(6F)); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java index 6d846d8ec..acabc9f78 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/choice/Choice8Test.java @@ -12,6 +12,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.choice.Choice8.a; @@ -50,7 +51,13 @@ public void setUp() { h = h((short) 7); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + BifunctorLaws.class, + TraversableLaws.class, + MonadRecLaws.class}) public Subjects> testSubjects() { return subjects(a("foo"), b(1), c(true), d('a'), e(2d), f(5L), g(6F), h((short) 7)); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index c66438442..3e7629949 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -10,6 +10,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import java.util.HashMap; @@ -39,7 +40,13 @@ public void setUp() { tuple2 = new Tuple2<>(1, new SingletonHList<>(2)); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + BifunctorLaws.class, + TraversableLaws.class}) public Tuple2 testSubject() { return tuple("one", 2); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index 766344de3..39400c6b0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -8,6 +8,7 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadReaderLaws; import testsupport.traits.MonadWriterLaws; @@ -30,6 +31,7 @@ public class Fn1Test { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, + MonadRecLaws.class, MonadReaderLaws.class, MonadWriterLaws.class}) public Equivalence> testSubject() { diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java index 15bc63f74..fab19faa6 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java @@ -8,6 +8,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.functor.builtin.Const.pureConst; @@ -16,7 +17,13 @@ @RunWith(Traits.class) public class ConstTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + BifunctorLaws.class, + TraversableLaws.class}) public Const testSubject() { return new Const<>(1); } diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java index 0699d4f5b..45785399b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/LazyTest.java @@ -9,6 +9,7 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import java.util.concurrent.atomic.AtomicBoolean; @@ -24,7 +25,7 @@ @RunWith(Traits.class) public class LazyTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) public Equivalence> testSubject() { return equivalence(lazy(0), Lazy::value); } diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java index 2f79ffe85..9814d5ee0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/MarketTest.java @@ -9,6 +9,7 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.trying; @@ -23,7 +24,7 @@ @RunWith(Traits.class) public class MarketTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) public Subjects>> testSubject() { Market market = new Market<>(id(), str -> trying(() -> parseInt(str), constantly(str))); diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java index 1a22282b6..fba168ecd 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java @@ -13,6 +13,7 @@ import testsupport.traits.MonadLaws; import testsupport.traits.MonadReaderLaws; import testsupport.traits.MonadWriterLaws; +import testsupport.traits.MonadRecLaws; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; @@ -26,6 +27,7 @@ public class StateTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, + MonadRecLaws.class, MonadReaderLaws.class, MonadWriterLaws.class}) public Equivalence> testSubject() { diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/TaggedTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/TaggedTest.java index 085c1fc78..44b38acbd 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/TaggedTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/TaggedTest.java @@ -10,11 +10,12 @@ import testsupport.traits.TraversableLaws; import static org.junit.Assert.assertEquals; +import testsupport.traits.MonadRecLaws; @RunWith(Traits.class) public class TaggedTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class, MonadRecLaws.class}) public Tagged testSubject() { return new Tagged<>(1); } diff --git a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java index fa3291408..723abb4fc 100644 --- a/src/test/java/com/jnape/palatable/lambda/io/IOTest.java +++ b/src/test/java/com/jnape/palatable/lambda/io/IOTest.java @@ -14,6 +14,7 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import java.io.IOException; import java.util.ArrayList; @@ -63,7 +64,7 @@ public class IOTest { public @Rule ExpectedException thrown = ExpectedException.none(); - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) public Equivalence> testSubject() { return equivalence(io(1), IO::unsafePerformIO); } diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java index c5116c2e3..3fdd45f03 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java @@ -10,6 +10,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; @@ -24,7 +25,12 @@ @RunWith(Traits.class) public class EitherTTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + BifunctorLaws.class, + MonadRecLaws.class}) public Subjects, String, Integer>> testSubject() { return subjects(eitherT(new Identity<>(left("foo"))), eitherT(new Identity<>(right(1)))); } diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java index 44e17b6f0..0d31de5d8 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java @@ -9,6 +9,7 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; @@ -21,7 +22,7 @@ @RunWith(Traits.class) public class IdentityTTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) public IdentityT, Integer> testSubject() { return identityT(just(new Identity<>(1))); } diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java index 30fbfb9df..8daa73bbe 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java @@ -9,6 +9,7 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; @@ -21,7 +22,7 @@ @RunWith(Traits.class) public class LazyTTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) public LazyT, Integer> testSubject() { return lazyT(just(lazy(1))); } diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java index 57273d87c..cba72968a 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java @@ -10,6 +10,7 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; @@ -25,7 +26,7 @@ @RunWith(Traits.class) public class MaybeTTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) public Subjects, Integer>> testSubject() { return subjects(maybeT(right(just(1))), maybeT(right(nothing())), diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java index b709f7957..55ee2eec7 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java @@ -10,6 +10,7 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadReaderLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -21,7 +22,7 @@ @RunWith(Traits.class) public class ReaderTTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadReaderLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadReaderLaws.class, MonadRecLaws.class}) public Equivalence, Integer>> testSubject() { return equivalence(readerT(Identity::new), readerT -> readerT.runReaderT(1)); } diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java index 18efdf5c5..f36d660ef 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java @@ -12,6 +12,7 @@ import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; import testsupport.traits.MonadReaderLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadWriterLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -27,6 +28,7 @@ public class StateTTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, + MonadRecLaws.class, MonadReaderLaws.class, MonadWriterLaws.class}) public Equivalence, Integer>> testReader() { diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java index 26a571297..a1e3f0531 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java @@ -1,5 +1,6 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; +import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -10,10 +11,14 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadWriterLaws; +import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +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.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.monad.transformer.builtin.WriterT.writerT; import static com.jnape.palatable.lambda.monoid.builtin.Join.join; @@ -23,7 +28,7 @@ @RunWith(Traits.class) public class WriterTTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadWriterLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadWriterLaws.class, MonadRecLaws.class}) public Equivalence, Integer>> testSubject() { return equivalence(writerT(new Identity<>(tuple(2, ""))), writerT -> writerT.runWriterT(join())); } diff --git a/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java index 48ab32b73..8c2bdb79f 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/IsoTest.java @@ -9,6 +9,7 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import java.util.List; @@ -27,7 +28,7 @@ public class IsoTest { private static final Iso, Integer, Double> ISO = iso(Integer::parseInt, dbl -> dbl.toString().chars().mapToObj(x -> (char) x).collect(toList())); - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) public Equivalence, Integer, Double>> testSubject() { return equivalence(ISO, iso -> view(iso, "123")); } diff --git a/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java b/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java index 60821aed0..8283cd4d4 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/LensTest.java @@ -13,6 +13,7 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import java.util.List; import java.util.Map; @@ -42,7 +43,7 @@ public class LensTest { private static final Lens, Set, String, Integer> LENS = lens(xs -> xs.get(0), (xs, i) -> singleton(i)); - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) public Equivalence, List, Integer, String>> testSubject() { return equivalence(lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s))), lens -> view(lens, emptyMap())); } diff --git a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java index ab36ff51f..22e2c5541 100644 --- a/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java +++ b/src/test/java/com/jnape/palatable/lambda/optics/PrismTest.java @@ -11,6 +11,7 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; @@ -34,7 +35,7 @@ public class PrismTest { private static final Fn1 PARSE_INT = Fn1.fn1(Integer::parseInt); - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) public Equivalence> testSubject() { return equivalence(Prism.fromPartial(Integer::parseInt, Object::toString), prism -> matching(prism, "foo")); diff --git a/src/test/java/testsupport/traits/MonadRecLaws.java b/src/test/java/testsupport/traits/MonadRecLaws.java index 2551e9ecc..00f96eb45 100644 --- a/src/test/java/testsupport/traits/MonadRecLaws.java +++ b/src/test/java/testsupport/traits/MonadRecLaws.java @@ -1,25 +1,43 @@ package testsupport.traits; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.MonadRec; -import com.jnape.palatable.traitor.traits.Trait; +import com.jnape.palatable.lambda.monoid.builtin.Present; -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.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static java.util.Collections.singletonList; import static testsupport.Constants.STACK_EXPLODING_NUMBER; -public class MonadRecLaws> implements Trait> { +public class MonadRecLaws> implements EquivalenceTrait> { @Override - public void test(MonadRec monadRec) { + public Class> type() { + return MonadRec.class; + } + @Override + public void test(Equivalence> equivalence) { + Present.present((x, y) -> x + "\n\t - " + y) + .>, Maybe>>foldMap( + fn -> fn.apply(equivalence), + singletonList(this::testStackSafety)) + .match(IO::io, + s -> IO.throwing(new AssertionError("The following MonadRec laws did not hold for instance of " + + equivalence + ": \n\t - " + s))) + .unsafePerformIO(); + } - boolean equals = monadRec.pure(STACK_EXPLODING_NUMBER) - .equals(monadRec.pure(0) - .trampolineM(x -> monadRec.pure(x < STACK_EXPLODING_NUMBER - ? recurse(x + 1) - : terminate(x)))); - if (!equals) - throw new AssertionError("Expected m.pure(" + STACK_EXPLODING_NUMBER + ") == " + - "m.pure(0).trampolineM(f)"); + private Maybe testStackSafety(Equivalence> equivalence) { + return equivalence.invMap(mr -> mr.pure(0) + .trampolineM(x -> mr.pure(x < STACK_EXPLODING_NUMBER + ? RecursiveResult.recurse(x + 1) + : RecursiveResult.terminate(x)))) + .equals(equivalence.invMap(mr -> mr.pure(STACK_EXPLODING_NUMBER))) + ? nothing() + : just("stack-safety (m.pure(" + STACK_EXPLODING_NUMBER + ").equals(m.pure(0).trampolineM(f)))"); } } From 99b8d4845515173734fc903668b88dbf5d943867 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 11 Sep 2019 10:38:52 -0500 Subject: [PATCH 245/348] whoops, forgot these: adding MonadRec to Tuple3-8 --- .../palatable/lambda/adt/hlist/Tuple2.java | 1 - .../palatable/lambda/adt/hlist/Tuple3.java | 22 ++++++++++++---- .../palatable/lambda/adt/hlist/Tuple4.java | 22 ++++++++++++---- .../palatable/lambda/adt/hlist/Tuple5.java | 24 ++++++++++++----- .../palatable/lambda/adt/hlist/Tuple6.java | 25 +++++++++++++----- .../palatable/lambda/adt/hlist/Tuple7.java | 25 +++++++++++++----- .../palatable/lambda/adt/hlist/Tuple8.java | 26 ++++++++++++++----- .../lambda/adt/hlist/Tuple2Test.java | 2 ++ .../lambda/adt/hlist/Tuple3Test.java | 9 ++++++- .../lambda/adt/hlist/Tuple4Test.java | 9 ++++++- .../lambda/adt/hlist/Tuple5Test.java | 9 ++++++- .../lambda/adt/hlist/Tuple6Test.java | 9 ++++++- .../lambda/adt/hlist/Tuple7Test.java | 9 ++++++- .../lambda/adt/hlist/Tuple8Test.java | 9 ++++++- 14 files changed, 160 insertions(+), 41 deletions(-) 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 81533a578..2f59fb7e7 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 @@ -37,7 +37,6 @@ */ public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements Product2<_1, _2>, - Map.Entry<_1, _2>, MonadRec<_2, Tuple2<_1, ?>>, MonadWriter<_1, _2, Tuple2<_1, ?>>, Bifunctor<_1, _2, Tuple2>, 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 f0e91cfae..f84af1061 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 @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.adt.product.Product3; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * A 3-element tuple product type, implemented as a specialized HList. Supports random access. @@ -30,7 +33,7 @@ */ public class Tuple3<_1, _2, _3> extends HCons<_1, Tuple2<_2, _3>> implements Product3<_1, _2, _3>, - Monad<_3, Tuple3<_1, _2, ?>>, + MonadRec<_3, Tuple3<_1, _2, ?>>, Bifunctor<_2, _3, Tuple3<_1, ?, ?>>, Traversable<_3, Tuple3<_1, _2, ?>> { @@ -107,7 +110,7 @@ public Tuple3<_2, _1, _3> invert() { @Override @SuppressWarnings("unchecked") public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Fn1 fn) { - return (Tuple3<_1, _2, _3Prime>) Monad.super.fmap(fn); + return (Tuple3<_1, _2, _3Prime>) MonadRec.super.fmap(fn); } /** @@ -160,7 +163,7 @@ public <_3Prime> Tuple3<_1, _2, _3Prime> zip( @Override public <_3Prime> Lazy> lazyZip( Lazy, Tuple3<_1, _2, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_3Prime, Tuple3<_1, _2, ?>>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad<_3Prime, Tuple3<_1, _2, ?>>::coerce); } /** @@ -168,7 +171,7 @@ public <_3Prime> Lazy> lazyZip( */ @Override public <_3Prime> Tuple3<_1, _2, _3Prime> discardL(Applicative<_3Prime, Tuple3<_1, _2, ?>> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -176,7 +179,7 @@ public <_3Prime> Tuple3<_1, _2, _3Prime> discardL(Applicative<_3Prime, Tuple3<_1 */ @Override public <_3Prime> Tuple3<_1, _2, _3> discardR(Applicative<_3Prime, Tuple3<_1, _2, ?>> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -188,6 +191,15 @@ public <_3Prime> Tuple3<_1, _2, _3Prime> flatMap( return pure(f.apply(_3).>coerce()._3); } + /** + * {@inheritDoc} + */ + @Override + public <_3Prime> Tuple3<_1, _2, _3Prime> trampolineM( + Fn1, Tuple3<_1, _2, ?>>> fn) { + return fmap(trampoline(x -> fn.apply(x).>>coerce()._3())); + } + /** * {@inheritDoc} */ 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 a629fa737..3e74da859 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 @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.adt.product.Product4; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * A 4-element tuple product type, implemented as a specialized HList. Supports random access. @@ -31,7 +34,7 @@ */ public class Tuple4<_1, _2, _3, _4> extends HCons<_1, Tuple3<_2, _3, _4>> implements Product4<_1, _2, _3, _4>, - Monad<_4, Tuple4<_1, _2, _3, ?>>, + MonadRec<_4, Tuple4<_1, _2, _3, ?>>, Bifunctor<_3, _4, Tuple4<_1, _2, ?, ?>>, Traversable<_4, Tuple4<_1, _2, _3, ?>> { @@ -133,7 +136,7 @@ public Tuple4<_2, _1, _3, _4> invert() { */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> fmap(Fn1 fn) { - return (Tuple4<_1, _2, _3, _4Prime>) Monad.super.<_4Prime>fmap(fn); + return (Tuple4<_1, _2, _3, _4Prime>) MonadRec.super.<_4Prime>fmap(fn); } /** @@ -184,7 +187,7 @@ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> zip( @Override public <_4Prime> Lazy> lazyZip( Lazy, Tuple4<_1, _2, _3, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_4Prime, Tuple4<_1, _2, _3, ?>>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad<_4Prime, Tuple4<_1, _2, _3, ?>>::coerce); } /** @@ -192,7 +195,7 @@ public <_4Prime> Lazy> lazyZip( */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4Prime> discardL(Applicative<_4Prime, Tuple4<_1, _2, _3, ?>> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -200,7 +203,7 @@ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> discardL(Applicative<_4Prime, Tuple */ @Override public <_4Prime> Tuple4<_1, _2, _3, _4> discardR(Applicative<_4Prime, Tuple4<_1, _2, _3, ?>> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -212,6 +215,15 @@ public <_4Prime> Tuple4<_1, _2, _3, _4Prime> flatMap( return pure(f.apply(_4).>coerce()._4); } + /** + * {@inheritDoc} + */ + @Override + public <_4Prime> Tuple4<_1, _2, _3, _4Prime> trampolineM( + Fn1, Tuple4<_1, _2, _3, ?>>> fn) { + return fmap(trampoline(x -> fn.apply(x).>>coerce()._4())); + } + /** * {@inheritDoc} */ 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 53595a42c..3c9e4e941 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 @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.adt.product.Product5; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * A 5-element tuple product type, implemented as a specialized HList. Supports random access. @@ -32,7 +35,7 @@ */ public class Tuple5<_1, _2, _3, _4, _5> extends HCons<_1, Tuple4<_2, _3, _4, _5>> implements Product5<_1, _2, _3, _4, _5>, - Monad<_5, Tuple5<_1, _2, _3, _4, ?>>, + MonadRec<_5, Tuple5<_1, _2, _3, _4, ?>>, Bifunctor<_4, _5, Tuple5<_1, _2, _3, ?, ?>>, Traversable<_5, Tuple5<_1, _2, _3, _4, ?>> { @@ -160,7 +163,7 @@ public Tuple5<_2, _1, _3, _4, _5> invert() { */ @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Fn1 fn) { - return Monad.super.<_5Prime>fmap(fn).coerce(); + return MonadRec.super.<_5Prime>fmap(fn).coerce(); } /** @@ -204,7 +207,7 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> pure(_5Prime _5Prime) { @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> zip( Applicative, Tuple5<_1, _2, _3, _4, ?>> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -213,7 +216,7 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> zip( @Override public <_5Prime> Lazy> lazyZip( Lazy, Tuple5<_1, _2, _3, _4, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_5Prime, Tuple5<_1, _2, _3, _4, ?>>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad<_5Prime, Tuple5<_1, _2, _3, _4, ?>>::coerce); } /** @@ -221,7 +224,7 @@ public <_5Prime> Lazy> lazyZip( */ @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> discardL(Applicative<_5Prime, Tuple5<_1, _2, _3, _4, ?>> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -229,7 +232,7 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> discardL(Applicative<_5Prime, T */ @Override public <_5Prime> Tuple5<_1, _2, _3, _4, _5> discardR(Applicative<_5Prime, Tuple5<_1, _2, _3, _4, ?>> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -241,6 +244,15 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> flatMap( return pure(f.apply(_5).>coerce()._5()); } + /** + * {@inheritDoc} + */ + @Override + public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> trampolineM( + Fn1, Tuple5<_1, _2, _3, _4, ?>>> fn) { + return fmap(trampoline(x -> fn.apply(x).>>coerce()._5())); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 3e33d97bb..e7d21dcff 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.adt.product.Product6; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * A 6-element tuple product type, implemented as a specialized HList. Supports random access. @@ -34,7 +37,7 @@ */ public class Tuple6<_1, _2, _3, _4, _5, _6> extends HCons<_1, Tuple5<_2, _3, _4, _5, _6>> implements Product6<_1, _2, _3, _4, _5, _6>, - Monad<_6, Tuple6<_1, _2, _3, _4, _5, ?>>, + MonadRec<_6, Tuple6<_1, _2, _3, _4, _5, ?>>, Bifunctor<_5, _6, Tuple6<_1, _2, _3, _4, ?, ?>>, Traversable<_6, Tuple6<_1, _2, _3, _4, _5, ?>> { @@ -188,7 +191,7 @@ public Tuple6<_2, _1, _3, _4, _5, _6> invert() { */ @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> fmap(Fn1 fn) { - return Monad.super.<_6Prime>fmap(fn).coerce(); + return MonadRec.super.<_6Prime>fmap(fn).coerce(); } /** @@ -233,7 +236,7 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> pure(_6Prime _6Prime) { @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> zip( Applicative, Tuple6<_1, _2, _3, _4, _5, ?>> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -242,7 +245,7 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> zip( @Override public <_6Prime> Lazy> lazyZip( Lazy, Tuple6<_1, _2, _3, _4, _5, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>>::coerce); } /** @@ -251,7 +254,7 @@ public <_6Prime> Lazy> lazyZip( @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> discardL( Applicative<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -259,7 +262,7 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> discardL( */ @Override public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6> discardR(Applicative<_6Prime, Tuple6<_1, _2, _3, _4, _5, ?>> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -271,6 +274,16 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> flatMap( return pure(f.apply(_6).>coerce()._6()); } + /** + * {@inheritDoc} + */ + @Override + public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> trampolineM( + Fn1, Tuple6<_1, _2, _3, _4, _5, ?>>> fn) { + return fmap(trampoline(x -> fn.apply(x).>>coerce() + ._6())); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index f352b5438..c65cda76a 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.adt.product.Product7; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * A 7-element tuple product type, implemented as a specialized HList. Supports random access. @@ -36,7 +39,7 @@ */ public class Tuple7<_1, _2, _3, _4, _5, _6, _7> extends HCons<_1, Tuple6<_2, _3, _4, _5, _6, _7>> implements Product7<_1, _2, _3, _4, _5, _6, _7>, - Monad<_7, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, + MonadRec<_7, Tuple7<_1, _2, _3, _4, _5, _6, ?>>, Bifunctor<_6, _7, Tuple7<_1, _2, _3, _4, _5, ?, ?>>, Traversable<_7, Tuple7<_1, _2, _3, _4, _5, _6, ?>> { @@ -216,7 +219,7 @@ public Tuple7<_2, _1, _3, _4, _5, _6, _7> invert() { */ @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> fmap(Fn1 fn) { - return Monad.super.<_7Prime>fmap(fn).coerce(); + return MonadRec.super.<_7Prime>fmap(fn).coerce(); } /** @@ -261,7 +264,7 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> pure(_7Prime _7Prime) { @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> zip( Applicative, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -270,7 +273,7 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> zip( @Override public <_7Prime> Lazy> lazyZip( Lazy, Tuple7<_1, _2, _3, _4, _5, _6, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>>::coerce); } /** @@ -279,7 +282,7 @@ public <_7Prime> Lazy> lazyZip( @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> discardL( Applicative<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -288,7 +291,7 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> discardL( @Override public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7> discardR( Applicative<_7Prime, Tuple7<_1, _2, _3, _4, _5, _6, ?>> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -300,6 +303,16 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> flatMap( return pure(f.apply(_7).>coerce()._7()); } + /** + * {@inheritDoc} + */ + @Override + public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> trampolineM( + Fn1, Tuple7<_1, _2, _3, _4, _5, _6, ?>>> fn) { + return fmap(trampoline(x -> fn.apply(x).>>coerce() + ._7())); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 1287b275e..21ca92738 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -5,15 +5,18 @@ import com.jnape.palatable.lambda.adt.product.Product8; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn2.Into; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Uncons.uncons; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; /** * An 8-element tuple product type, implemented as a specialized HList. Supports random access. @@ -38,7 +41,7 @@ */ public class Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> extends HCons<_1, Tuple7<_2, _3, _4, _5, _6, _7, _8>> implements Product8<_1, _2, _3, _4, _5, _6, _7, _8>, - Monad<_8, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, + MonadRec<_8, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>, Bifunctor<_7, _8, Tuple8<_1, _2, _3, _4, _5, _6, ?, ?>>, Traversable<_8, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> { @@ -244,7 +247,7 @@ public Tuple8<_2, _1, _3, _4, _5, _6, _7, _8> invert() { */ @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> fmap(Fn1 fn) { - return Monad.super.<_8Prime>fmap(fn).coerce(); + return MonadRec.super.<_8Prime>fmap(fn).coerce(); } /** @@ -289,7 +292,7 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> pure(_8Prime _8Prim @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> zip( Applicative, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -299,7 +302,7 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> zip( public <_8Prime> Lazy> lazyZip( Lazy, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>::coerce); } /** @@ -308,7 +311,7 @@ public <_8Prime> Lazy> lazyZip( @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> discardL( Applicative<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -317,7 +320,7 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> discardL( @Override public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> discardR( Applicative<_8Prime, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -329,6 +332,17 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> flatMap( return pure(f.apply(_8).>coerce()._8()); } + /** + * {@inheritDoc} + */ + @Override + public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> trampolineM( + Fn1, Tuple8<_1, _2, _3, _4, _5, _6, _7, ?>>> fn) { + return fmap(trampoline(x -> fn.apply(x) + .>>coerce() + ._8())); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index 3e7629949..32483a168 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -11,6 +11,7 @@ import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; import testsupport.traits.MonadRecLaws; +import testsupport.traits.MonadWriterLaws; import testsupport.traits.TraversableLaws; import java.util.HashMap; @@ -45,6 +46,7 @@ public void setUp() { ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class, + MonadWriterLaws.class, BifunctorLaws.class, TraversableLaws.class}) public Tuple2 testSubject() { diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java index d9d3b64ff..9ac57fcfb 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java @@ -10,6 +10,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -35,7 +36,13 @@ public void setUp() { tuple3 = new Tuple3<>(1, new Tuple2<>("2", new SingletonHList<>('3'))); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + BifunctorLaws.class, + TraversableLaws.class}) public Tuple3 testSubject() { return tuple("one", 2, 3d); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java index ffd188a43..b2a1d6319 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java @@ -10,6 +10,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -35,7 +36,13 @@ public void setUp() { tuple4 = new Tuple4<>(1, new Tuple3<>("2", new Tuple2<>('3', new SingletonHList<>(false)))); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + BifunctorLaws.class, + TraversableLaws.class}) public Tuple4 testSubject() { return tuple("one", 2, 3d, 4f); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index 45236d2f1..83b300b97 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -11,6 +11,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -36,7 +37,13 @@ public void setUp() { tuple5 = new Tuple5<>(1, new Tuple4<>("2", new Tuple3<>('3', new Tuple2<>(false, new SingletonHList<>(5L))))); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + BifunctorLaws.class, + TraversableLaws.class}) public Tuple5 testSubject() { return tuple("one", 2, 3d, 4f, '5'); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index 604dee77f..902b4b254 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -11,6 +11,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -36,7 +37,13 @@ public void setUp() { tuple6 = new Tuple6<>(2.0f, new Tuple5<>(1, new Tuple4<>("2", new Tuple3<>('3', new Tuple2<>(false, new SingletonHList<>(5L)))))); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + BifunctorLaws.class, + TraversableLaws.class}) public Tuple6 testSubject() { return tuple("one", 2, 3d, 4f, '5', (byte) 6); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index 22d8bcc84..0e8a68aec 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -11,6 +11,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -36,7 +37,13 @@ public void setUp() { tuple7 = new Tuple7<>((byte) 127, new Tuple6<>(2.0f, new Tuple5<>(1, new Tuple4<>("2", new Tuple3<>('3', new Tuple2<>(false, new SingletonHList<>(5L))))))); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + BifunctorLaws.class, + TraversableLaws.class}) public Tuple7 testSubject() { return tuple("one", 2, 3d, 4f, '5', (byte) 6, 7L); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java index 6f67a6cb6..4d2a8cb76 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java @@ -11,6 +11,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -38,7 +39,13 @@ public void setUp() { tuple8 = new Tuple8<>((short) 65535, new Tuple7<>((byte) 127, new Tuple6<>(2.0f, new Tuple5<>(1, tuple4)))); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) + @TestTraits({ + FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + BifunctorLaws.class, + TraversableLaws.class}) public Tuple8 testSubject() { return tuple("one", 2, 3d, 4f, '5', (byte) 6, 7L, (short) 65535); } From 559bfb3885f1d714df05d6141c26ea6d1353b216 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 10 Sep 2019 16:08:08 -0500 Subject: [PATCH 246/348] Adding SafeT, a stack-safe transformer for any MonadRec --- .../lambda/functions/specialized/Pure.java | 12 + .../palatable/lambda/monad/MonadRec.java | 3 + .../jnape/palatable/lambda/monad/SafeT.java | 300 ++++++++++++++++++ .../palatable/lambda/monad/SafeTTest.java | 76 +++++ 4 files changed, 391 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/SafeT.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monad/SafeTTest.java diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java index 77d3bd91a..4e8737cd7 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java @@ -33,4 +33,16 @@ public interface Pure> { static > Pure pure(Pure pure) { return pure; } + + /** + * Extract an {@link Applicative Applicative's} {@link Applicative#pure(Object) pure} implementation to an instance + * of {@link Pure}. + * + * @param app the {@link Applicative} + * @param the witness + * @return the {@link Pure} + */ + static > Pure of(Applicative app) { + return app::pure; + } } diff --git a/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java b/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java index 8d4492422..b55fb5aa8 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/MonadRec.java @@ -13,6 +13,9 @@ /** * A class of {@link Monad monads} that offer a stack-safe interface for performing arbitrarily many * {@link Monad#flatMap(Fn1) flatmap-like} operations via {@link MonadRec#trampolineM(Fn1)}. + *

+ * Inspired by Phil Freeman's paper + * _Stack Safety for Free_ * * @param the carrier type * @param the {@link MonadRec witness} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/SafeT.java b/src/main/java/com/jnape/palatable/lambda/monad/SafeT.java new file mode 100644 index 000000000..9eada32da --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/SafeT.java @@ -0,0 +1,300 @@ +package com.jnape.palatable.lambda.monad; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.coproduct.CoProduct2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; +import com.jnape.palatable.lambda.functions.recursion.Trampoline; +import com.jnape.palatable.lambda.functions.specialized.Lift; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.recurse; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; + +/** + * A stack-safe {@link MonadT monad transformer} that can safely interpret deeply nested left- or right-associated + * binds for any {@link MonadRec}. + *

+ * Example: + *

+ * {@code
+ * Times.>times(100_000, f -> f.fmap(x -> x + 1), id()).apply(0); // stack-overflow
+ * Times., Integer>>times(100_000, f -> f.fmap(x -> x + 1), safeT(id()))
+ *         .>runSafeT()
+ *         .apply(0); // 100_000
+ * }
+ * 
+ *

+ * Inspired by Phil Freeman's paper + * Stack Safety for Free. + * + * @param the {@link MonadRec} instance + * @param the carrier type + */ +public final class SafeT, A> implements + MonadT, SafeT> { + + private final Body body; + private final Pure pureM; + + private SafeT(Body body, Pure pureM) { + this.body = body; + this.pureM = pureM; + } + + /** + * Recover the full structure of the embedded {@link Monad} in a stack-safe way. + * + * @param the witnessed target type + * @return the embedded {@link Monad} + */ + public > MA runSafeT() { + return body.resume().match( + fFree -> fFree.trampolineM(freeF -> freeF.resume().match( + monadRec -> monadRec.fmap(RecursiveResult::recurse), + a -> pureM.>apply(a).fmap(RecursiveResult::terminate))).coerce(), + pureM::apply); + } + + /** + * {@inheritDoc} + */ + @Override + public SafeT fmap(Fn1 fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public > SafeT lift(MonadRec nb) { + return liftSafeT().apply(nb); + } + + /** + * {@inheritDoc} + */ + @Override + public SafeT flatMap(Fn1>> f) { + return new SafeT<>(Body.suspend(body, a -> f.apply(a).>coerce().body), pureM); + } + + /** + * {@inheritDoc} + */ + @Override + public SafeT zip(Applicative, SafeT> appFn) { + return body.resume() + .match(mBodyA -> appFn.>>coerce().body.resume() + .match(mBodyF -> new SafeT<>(Body.more(mBodyA.zip(mBodyF.fmap( + bodyF -> bodyA -> new SafeT<>(bodyA, pureM).zip(new SafeT<>(bodyF, pureM)).body))), pureM), + f -> new SafeT<>(Body.more(mBodyA.fmap(b -> Body.suspend( + b, a -> Body.done(f.apply(a))))), pureM)), + a -> appFn.>>coerce().body.resume() + .match(mBodyF -> new SafeT<>(new Body.More<>(mBodyF.fmap( + body -> new SafeT<>(body, pureM).fmap(f -> f.apply(a)).body)), pureM), + f -> pure(f.apply(a)))); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, SafeT>> lazyAppFn) { + return MonadT.super.lazyZip(lazyAppFn).fmap(Applicative>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + public SafeT discardL(Applicative> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public SafeT discardR(Applicative> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public SafeT pure(B b) { + return pureSafeT(pureM).apply(b); + } + + /** + * {@inheritDoc} + */ + @Override + public SafeT trampolineM(Fn1, SafeT>> bounce) { + return flatMap(bounce.fmap(mab -> mab.flatMap(aOrB -> aOrB + .match(a -> mab.pure(a).trampolineM(bounce), Pure.of(mab)::apply)))); + } + + /** + * Lift any {@link MonadRec MonadRec}<A, M> into a {@link SafeT SafeT}<M, A>. + * + * @param ma the {@link MonadRec MonadRec}<A, M> + * @param the {@link MonadRec} witness + * @param the carrier type + * @return the new {@link SafeT} + */ + public static , A> SafeT safeT(MonadRec ma) { + return new SafeT<>(new Body.More<>(ma.fmap(Body.Done::new)), Pure.of(ma)); + } + + /** + * The canonical {@link Pure} instance for {@link SafeT}. + * + * @param pureM the argument {@link Monad} {@link Pure} + * @param the argument {@link Monad} witness + * @return the {@link Pure} instance + */ + public static > Pure> pureSafeT(Pure pureM) { + return new Pure>() { + @Override + public SafeT checkedApply(A a) throws Throwable { + return safeT(pureM.>apply(a)); + } + }; + } + + /** + * {@link Lift} for {@link SafeT}. + * + * @return the {@link Monad} lifted into {@link SafeT} + */ + public static Lift> liftSafeT() { + return SafeT::safeT; + } + + private abstract static class Body, A> implements + CoProduct2, M>, A>, Body.Suspended, Body> { + + private Body() { + } + + public abstract Either, M>, A> resume(); + + private static , A> Body done(A a) { + return new Done<>(a); + } + + private static , A> Body more(MonadRec, M> mb) { + return new More<>(mb); + } + + private static , A, B> Body suspend(Body freeA, Fn1> fn) { + return new SafeT.Body.Suspended<>(freeA, fn); + } + + private static final class Done, A> extends Body { + private final A a; + + private Done(A a) { + this.a = a; + } + + @Override + public R match(Fn1, M>, A>, ? extends R> aFn, + Fn1, ? extends R> bFn) { + return aFn.apply(right(a)); + } + + @Override + public Either, M>, A> resume() { + return right(a); + } + } + + private static final class More, A> extends Body { + private final MonadRec, M> mfa; + + private More(MonadRec, M> mfa) { + this.mfa = mfa; + } + + @Override + public R match(Fn1, M>, A>, ? extends R> aFn, + Fn1, ? extends R> bFn) { + return aFn.apply(left(mfa)); + } + + @Override + public Either, M>, A> resume() { + return left(mfa); + } + } + + private static final class Suspended, A, B> extends Body { + private final Body source; + private final Fn1> f; + + private Suspended(Body source, Fn1> f) { + this.source = source; + this.f = f; + } + + public Either, M>, B> resume() { + Φ, Either, M>, B>>> phi = + new Φ, Either, M>, B>>>() { + @Override + public RecursiveResult, Either, M>, B>> apply( + Body source, Fn1> f) { + return source.match( + e -> e.match(more -> terminate(left(more.fmap(body -> suspend(body, f)))), + z -> recurse(f.apply(z))), + associateRight(f)); + } + }; + return Trampoline., Either, M>, B>>trampoline( + free -> free.match(RecursiveResult::terminate, suspended -> suspended.eliminate(phi)), + this); + } + + @Override + public R match(Fn1, M>, B>, ? extends R> aFn, + Fn1, ? extends R> bFn) { + return bFn.apply(this); + } + + private Fn1, RecursiveResult, Either, M>, B>>> + associateRight(Fn1> f) { + Φ, Either, M>, B>>> phi = + new Φ, Either, M>, B>>>() { + @Override + public RecursiveResult, Either, M>, B>> apply( + Body source, + Fn1> g) { + return recurse(suspend(source, x -> suspend(g.apply(x), f))); + } + }; + + return suspended -> suspended.eliminate(phi); + } + + @SuppressWarnings("NonAsciiCharacters") + private R eliminate(Φ Φ) { + return Φ.apply(source, f); + } + + @SuppressWarnings("NonAsciiCharacters") + private interface Φ, B, R> { + R apply(Body source, Fn1> fn); + } + } + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/SafeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/SafeTTest.java new file mode 100644 index 000000000..17206c5fa --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/SafeTTest.java @@ -0,0 +1,76 @@ +package com.jnape.palatable.lambda.monad; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn1.Id; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; + +import java.util.concurrent.CountDownLatch; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; +import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.monad.SafeT.safeT; +import static java.util.concurrent.Executors.newFixedThreadPool; +import static org.junit.Assert.assertEquals; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; +import static testsupport.traits.Equivalence.equivalence; + +@RunWith(Traits.class) +public class SafeTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) + public Equivalence, Integer>> testSubject() { + return equivalence(safeT(new Identity<>(1)), SafeT::>runSafeT); + } + + @Test + public void stackSafelyComposesMonadRecs() { + assertEquals(STACK_EXPLODING_NUMBER, + times(STACK_EXPLODING_NUMBER, f -> f.fmap(x -> x + 1), safeT(Id.id())) + .>runSafeT() + .apply(0)); + } + + @Test + public void flatMapStackSafety() { + assertEquals(new Identity<>(STACK_EXPLODING_NUMBER), + times(STACK_EXPLODING_NUMBER, + safeT -> safeT.flatMap(x -> safeT(new Identity<>(x + 1))), + safeT(new Identity<>(0))) + .runSafeT()); + } + + @Test + public void zipStackSafety() { + assertEquals(new Identity<>(STACK_EXPLODING_NUMBER), + times(STACK_EXPLODING_NUMBER, + safeT -> safeT.zip(safeT(new Identity<>(x -> x + 1))), + safeT(new Identity<>(0))).runSafeT()); + + } + + @Test(timeout = 500) + public void compositionallyPreservesZip() { + CountDownLatch latch = new CountDownLatch(2); + IO countDownAndAwait = io(() -> { + latch.countDown(); + latch.await(); + }); + + safeT(countDownAndAwait) + .discardL(safeT(countDownAndAwait)) + .>runSafeT() + .unsafePerformAsyncIO(newFixedThreadPool(2)) + .join(); + } +} \ No newline at end of file From 9671baa6624100fb2373c20ba5ba227368331ef7 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 16 Sep 2019 13:11:01 -0500 Subject: [PATCH 247/348] Fixing javadoc --- .../palatable/lambda/monad/transformer/builtin/ReaderT.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index e2624b381..1cc9f511e 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -49,6 +49,12 @@ public > MA runReaderT(R r) { /** * Map the current {@link Monad monadic} embedding to a new one in a potentially different {@link Monad}. + * + * @param fn the function + * @param the currently embedded {@link Monad} + * @param the new {@link Monad} witness + * @param the new carrier type + * @return the mapped {@link ReaderT} */ public , N extends MonadRec, B> ReaderT mapReaderT( Fn1> fn) { From 1f33cc360f52da32cd5f2d57dcc63c8f3becfad7 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 16 Sep 2019 13:15:35 -0500 Subject: [PATCH 248/348] Updating CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index faf73952a..3f9b47c81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `WriterT`, a monad transformer for an accumulation and a value - `EquivalenceTrait`, a traitor `Trait` to make it easier to test properties of type-classes with a separate equivalence relation +- `SafeT`, a stack-safe monad transformer for any `MonadRec` ### Deprecated - `Peek`, `Peek2`, `Maybe#peek`, and `Either#peek` in favor of explicitly matching into `IO` and running it From 5dd1fad7ee4ccbb0255263a3087292bd782c00a1 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 16 Sep 2019 15:13:03 -0500 Subject: [PATCH 249/348] RecursiveResult is now MonadRec --- .../functions/recursion/RecursiveResult.java | 79 ++++++++++++++++--- .../recursion/RecursiveResultTest.java | 3 +- 2 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java index a9f339db9..2fd54d791 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResult.java @@ -6,10 +6,13 @@ import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Sequence.sequence; + /** * Specialized {@link CoProduct2} representing the possible results of a primitive recursive function. * Used by {@link Trampoline} to cheat around {@link CoProduct2#match} and quickly unpack values via @@ -22,65 +25,107 @@ public abstract class RecursiveResult implements CoProduct2>, Bifunctor>, - Monad>, + MonadRec>, Traversable> { private RecursiveResult() { } + /** + * {@inheritDoc} + */ @Override public RecursiveResult invert() { return match(RecursiveResult::terminate, RecursiveResult::recurse); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") public RecursiveResult biMapL(Fn1 fn) { - return (RecursiveResult) Bifunctor.super.biMapL(fn); + return (RecursiveResult) Bifunctor.super.biMapL(fn); } + /** + * {@inheritDoc} + */ @Override - @SuppressWarnings("unchecked") public RecursiveResult biMapR(Fn1 fn) { - return (RecursiveResult) Bifunctor.super.biMapR(fn); + return (RecursiveResult) Bifunctor.super.biMapR(fn); } + /** + * {@inheritDoc} + */ @Override public RecursiveResult biMap(Fn1 lFn, Fn1 rFn) { return match(a -> recurse(lFn.apply(a)), b -> terminate(rFn.apply(b))); } + /** + * {@inheritDoc} + */ @Override public RecursiveResult flatMap(Fn1>> f) { return match(RecursiveResult::recurse, b -> f.apply(b).coerce()); } + /** + * {@inheritDoc} + */ @Override public RecursiveResult pure(C c) { return terminate(c); } + /** + * {@inheritDoc} + */ @Override public RecursiveResult fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } + /** + * {@inheritDoc} + */ @Override public RecursiveResult zip(Applicative, RecursiveResult> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override public RecursiveResult discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } + /** + * {@inheritDoc} + */ @Override public RecursiveResult discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public RecursiveResult trampolineM( + Fn1, RecursiveResult>> fn) { + return flatMap(Trampoline.>trampoline( + b -> sequence(fn.apply(b).>>coerce(), + RecursiveResult::terminate))); + } + + /** + * {@inheritDoc} + */ @Override public , TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, @@ -89,10 +134,26 @@ AppTrav extends Applicative> AppTrav traverse(Fn1 fn.apply(b).fmap(this::pure).fmap(RecursiveResult::coerce).coerce()); } + /** + * Static factory method for creating a "recurse" value. + * + * @param a the value + * @param the recurse type + * @param the terminate type + * @return the {@link RecursiveResult} + */ public static RecursiveResult recurse(A a) { return new Recurse<>(a); } + /** + * Static factory method for creating a "terminate" value. + * + * @param b the value + * @param the recurse type + * @param the terminate type + * @return the {@link RecursiveResult} + */ public static RecursiveResult terminate(B b) { return new Terminate<>(b); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java b/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java index d7d7c9fa4..d8a156a9a 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/recursion/RecursiveResultTest.java @@ -8,6 +8,7 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.recurse; @@ -18,7 +19,7 @@ @RunWith(Traits.class) public class RecursiveResultTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class, MonadRecLaws.class}) public Subjects> testSubject() { return subjects(recurse("foo"), terminate(1)); } From e207252fc8fc431065b753e5a1cb2460db1103f6 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 16 Sep 2019 15:13:48 -0500 Subject: [PATCH 250/348] Simplifying type signature --- .../java/com/jnape/palatable/lambda/adt/choice/Choice3.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 1d4263406..86b836068 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -34,10 +34,9 @@ */ public abstract class Choice3 implements CoProduct3>, - Monad>, + MonadRec>, Bifunctor>, - Traversable>, - MonadRec> { + Traversable> { private Choice3() { } From 82c40a40995379bc736f9bb2d6d1aabe6b716e46 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 17 Sep 2019 10:56:07 -0500 Subject: [PATCH 251/348] MonadRec instance for LambdaIterable --- CHANGELOG.md | 1 + .../iteration/TrampoliningIterator.java | 67 +++++++++++++++++ .../lambda/traversable/LambdaIterable.java | 29 ++++++-- .../iteration/TrampoliningIteratorTest.java | 72 +++++++++++++++++++ .../traversable/LambdaIterableTest.java | 36 +++++++++- 5 files changed, 199 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIterator.java create mode 100644 src/test/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIteratorTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f9b47c81..eabfad889 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `MonadError`, monads that can be thrown to and caught from, with defaults for `IO`, `Either`, `Maybe`, and `Try` +- `MonadRec`, monads that support a stack-safe `trampolineM` method with defaults for all exported monads - `Optic#andThen`, `Optic#compose`, and other defaults added - `Prism#andThen`, `Prism#compose` begets another `Prism` - `Prism#fromPartial` public interfaces diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIterator.java new file mode 100644 index 000000000..fa0350d08 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIterator.java @@ -0,0 +1,67 @@ +package com.jnape.palatable.lambda.internal.iteration; + +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Not.not; +import static com.jnape.palatable.lambda.io.IO.io; + +public final class TrampoliningIterator implements Iterator { + private final Fn1>> fn; + private final A a; + + private ImmutableQueue>> remaining; + private B b; + + public TrampoliningIterator(Fn1>> fn, A a) { + this.fn = fn; + this.a = a; + } + + @Override + public boolean hasNext() { + queueNextIfPossible(); + return b != null; + } + + @Override + public B next() { + if (!hasNext()) + throw new NoSuchElementException(); + B next = b; + b = null; + return next; + } + + private void queueNextIfPossible() { + if (remaining == null) + pruneAfter(() -> remaining = ImmutableQueue.>>empty() + .pushFront(fn.apply(a).iterator())); + + while (b == null && remaining.head().match(constantly(false), constantly(true))) { + tickNext(); + } + } + + private void tickNext() { + pruneAfter(() -> remaining.head().orElseThrow(NoSuchElementException::new).next()) + .match(a -> io(() -> { + pruneAfter(() -> remaining = remaining.pushFront(fn.apply(a).iterator())); + }), b -> io(() -> { + this.b = b; + })).unsafePerformIO(); + } + + private R pruneAfter(Fn0 fn) { + R r = fn.apply(); + while (remaining.head().match(constantly(false), not(Iterator::hasNext))) { + remaining = remaining.tail(); + } + return r; + } +} 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 379b40234..9859dac85 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -3,10 +3,13 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn1.Empty; import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.internal.iteration.TrampoliningIterator; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import java.util.Iterator; import java.util.Objects; @@ -24,7 +27,10 @@ * @param the {@link Iterable} element type * @see LambdaMap */ -public final class LambdaIterable implements Monad>, Traversable> { +public final class LambdaIterable implements + MonadRec>, + Traversable> { + private final Iterable as; @SuppressWarnings("unchecked") @@ -69,7 +75,7 @@ public LambdaIterable pure(B b) { */ @Override public LambdaIterable zip(Applicative, LambdaIterable> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -80,7 +86,7 @@ public Lazy> lazyZip( Lazy, LambdaIterable>> lazyAppFn) { return Empty.empty(as) ? lazy(LambdaIterable.empty()) - : Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); + : MonadRec.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -88,7 +94,7 @@ public Lazy> lazyZip( */ @Override public LambdaIterable discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -96,7 +102,7 @@ public LambdaIterable discardL(Applicative> appB) { */ @Override public LambdaIterable discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -107,6 +113,19 @@ public LambdaIterable flatMap(Fn1 f.apply(a).>coerce().unwrap(), as))); } + /** + * {@inheritDoc} + */ + @Override + public LambdaIterable trampolineM( + Fn1, LambdaIterable>> fn) { + return flatMap(a -> wrap(() -> new TrampoliningIterator<>( + x -> fn.apply(x) + .>>coerce() + .unwrap(), + a))); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIteratorTest.java new file mode 100644 index 000000000..81b37122c --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIteratorTest.java @@ -0,0 +1,72 @@ +package com.jnape.palatable.lambda.internal.iteration; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.recurse; +import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singleton; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class TrampoliningIteratorTest { + + @Test + public void hasNextIfAnyTerminateInstructions() { + TrampoliningIterator it = new TrampoliningIterator<>(x -> singleton(terminate(x + 1)), 0); + assertTrue(it.hasNext()); + assertEquals(1, it.next()); + assertFalse(it.hasNext()); + } + + @Test + public void hasNextIfTerminateInterleavedBeforeRecurse() { + TrampoliningIterator it = new TrampoliningIterator<>( + x -> x < 3 + ? asList(terminate(x), recurse(x + 1)) + : emptyList(), + 0); + assertTrue(it.hasNext()); + assertEquals(0, it.next()); + assertTrue(it.hasNext()); + assertEquals(1, it.next()); + assertTrue(it.hasNext()); + assertEquals(2, it.next()); + assertFalse(it.hasNext()); + } + + @Test + public void hasNextIfTerminateInterleavedAfterRecurse() { + TrampoliningIterator it = new TrampoliningIterator<>( + x -> x < 3 + ? asList(recurse(x + 1), terminate(x)) + : emptyList(), + 0); + assertTrue(it.hasNext()); + assertEquals(2, it.next()); + assertTrue(it.hasNext()); + assertEquals(1, it.next()); + assertTrue(it.hasNext()); + assertEquals(0, it.next()); + assertFalse(it.hasNext()); + } + + @Test + public void doesNotHaveNextIfEmptyInitialResult() { + TrampoliningIterator it = new TrampoliningIterator<>(constantly(emptyList()), 0); + assertFalse(it.hasNext()); + } + + @Test + public void doesNotHaveNextIfNoTerminateInstruction() { + TrampoliningIterator it = new TrampoliningIterator<>( + x -> x < 3 + ? singleton(recurse(x + 1)) + : emptyList(), + 0); + assertFalse(it.hasNext()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java index ead979b2c..ede9fde89 100644 --- a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java +++ b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaIterableTest.java @@ -10,6 +10,7 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.Maybe.just; @@ -19,6 +20,8 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Size.size; import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons; import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; +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.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.traversable.LambdaIterable.empty; import static com.jnape.palatable.lambda.traversable.LambdaIterable.pureLambdaIterable; @@ -26,6 +29,7 @@ import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.util.Arrays.asList; import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static testsupport.Constants.STACK_EXPLODING_NUMBER; @@ -34,11 +38,41 @@ @RunWith(Traits.class) public class LambdaIterableTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, TraversableLaws.class, MonadLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, TraversableLaws.class, MonadLaws.class, MonadRecLaws.class}) public Subjects> testSubject() { return subjects(LambdaIterable.empty(), wrap(singleton(1)), wrap(replicate(100, 1))); } + @Test + public void trampoliningWithDeferredResult() { + assertThat(LambdaIterable.wrap(singletonList(0)) + .trampolineM(x -> wrap(x < STACK_EXPLODING_NUMBER + ? singleton(recurse(x + 1)) + : singleton(terminate(x)))) + .unwrap(), + iterates(STACK_EXPLODING_NUMBER)); + } + + @Test + public void trampoliningOncePerElement() { + assertThat(LambdaIterable.wrap(asList(1, 2, 3)) + .trampolineM(x -> wrap(x < STACK_EXPLODING_NUMBER + ? singleton(recurse(x + 1)) + : singleton(terminate(x)))) + .unwrap(), + iterates(STACK_EXPLODING_NUMBER, STACK_EXPLODING_NUMBER, STACK_EXPLODING_NUMBER)); + } + + @Test + public void trampoliningWithIncrementalResults() { + assertThat(LambdaIterable.wrap(singletonList(0)) + .trampolineM(x -> wrap(x < 10 + ? asList(terminate(x), recurse(x + 1)) + : singleton(terminate(x)))) + .unwrap(), + iterates(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + } + @Test public void zipAppliesCartesianProductOfFunctionsAndValues() { LambdaIterable xs = wrap(asList(1, 2, 3)); From 21dfe755faf9e311b50014acad683d4e914e83bb Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 17 Sep 2019 11:15:30 -0500 Subject: [PATCH 252/348] MonadRec instance for SingletonHList and These --- .../com/jnape/palatable/lambda/adt/These.java | 36 +++++++++++++------ .../lambda/adt/hlist/SingletonHList.java | 25 +++++++++---- .../jnape/palatable/lambda/adt/TheseTest.java | 8 ++++- .../lambda/adt/hlist/SingletonHListTest.java | 3 +- 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index 38aba3ff6..6daad22dc 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -4,11 +4,14 @@ import com.jnape.palatable.lambda.adt.coproduct.CoProduct3; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; +import com.jnape.palatable.lambda.functions.recursion.Trampoline; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; import java.util.Objects; @@ -16,6 +19,7 @@ import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Sequence.sequence; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; /** @@ -28,7 +32,7 @@ */ public abstract class These implements CoProduct3, These>, - Monad>, + MonadRec>, Bifunctor>, Traversable> { @@ -58,6 +62,17 @@ public final These flatMap(Fn1 both(a, c))))); } + /** + * {@inheritDoc} + */ + @Override + public These trampolineM( + Fn1, These>> fn) { + return flatMap(Trampoline.>trampoline( + b -> sequence(fn.apply(b).>>coerce(), + RecursiveResult::terminate))); + } + /** * {@inheritDoc} */ @@ -66,6 +81,9 @@ public final These pure(C c) { return match(a -> both(a, c), b -> b(c), into((a, b) -> both(a, c))); } + /** + * {@inheritDoc} + */ @Override @SuppressWarnings("unchecked") public , TravB extends Traversable>, @@ -80,18 +98,16 @@ AppTrav traverse(Fn1> fn, Fn1 These biMapL(Fn1 fn) { - return (These) Bifunctor.super.biMapL(fn); + return (These) Bifunctor.super.biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public final These biMapR(Fn1 fn) { - return (These) Bifunctor.super.biMapR(fn); + return (These) Bifunctor.super.biMapR(fn); } /** @@ -99,7 +115,7 @@ public final These biMapR(Fn1 fn) { */ @Override public final These fmap(Fn1 fn) { - return Monad.super.fmap(fn).coerce(); + return MonadRec.super.fmap(fn).coerce(); } /** @@ -107,14 +123,14 @@ public final These fmap(Fn1 fn) { */ @Override public final These zip(Applicative, These> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } @Override public Lazy> lazyZip( Lazy, These>> lazyAppFn) { return projectA().>>fmap(a -> lazy(a(a))) - .orElseGet(() -> Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce)); + .orElseGet(() -> MonadRec.super.lazyZip(lazyAppFn).fmap(Monad>::coerce)); } /** @@ -122,7 +138,7 @@ public Lazy> lazyZip( */ @Override public final These discardL(Applicative> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -130,7 +146,7 @@ public final These discardL(Applicative> appB) { */ @Override public final These discardR(Applicative> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index 15eb94dca..927f27ae3 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -3,12 +3,16 @@ import com.jnape.palatable.lambda.adt.hlist.HList.HCons; import com.jnape.palatable.lambda.adt.hlist.HList.HNil; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.traversable.Traversable; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; + /** * A singleton HList. Supports random access. * @@ -20,7 +24,7 @@ * @see Tuple5 */ public class SingletonHList<_1> extends HCons<_1, HNil> implements - Monad<_1, SingletonHList>, + MonadRec<_1, SingletonHList>, Traversable<_1, SingletonHList> { SingletonHList(_1 _1) { @@ -40,7 +44,7 @@ public <_0> Tuple2<_0, _1> cons(_0 _0) { */ @Override public <_1Prime> SingletonHList<_1Prime> fmap(Fn1 fn) { - return Monad.super.<_1Prime>fmap(fn).coerce(); + return MonadRec.super.<_1Prime>fmap(fn).coerce(); } /** @@ -57,7 +61,7 @@ public <_1Prime> SingletonHList<_1Prime> pure(_1Prime _1Prime) { @Override public <_1Prime> SingletonHList<_1Prime> zip( Applicative, SingletonHList> appFn) { - return Monad.super.zip(appFn).coerce(); + return MonadRec.super.zip(appFn).coerce(); } /** @@ -66,7 +70,7 @@ public <_1Prime> SingletonHList<_1Prime> zip( @Override public <_1Prime> Lazy> lazyZip( Lazy, SingletonHList>> lazyAppFn) { - return Monad.super.lazyZip(lazyAppFn).fmap(Monad<_1Prime, SingletonHList>::coerce); + return MonadRec.super.lazyZip(lazyAppFn).fmap(Monad<_1Prime, SingletonHList>::coerce); } /** @@ -74,7 +78,7 @@ public <_1Prime> Lazy> lazyZip( */ @Override public <_1Prime> SingletonHList<_1Prime> discardL(Applicative<_1Prime, SingletonHList> appB) { - return Monad.super.discardL(appB).coerce(); + return MonadRec.super.discardL(appB).coerce(); } /** @@ -82,7 +86,7 @@ public <_1Prime> SingletonHList<_1Prime> discardL(Applicative<_1Prime, Singleton */ @Override public <_1Prime> SingletonHList<_1> discardR(Applicative<_1Prime, SingletonHList> appB) { - return Monad.super.discardR(appB).coerce(); + return MonadRec.super.discardR(appB).coerce(); } /** @@ -93,6 +97,15 @@ public <_1Prime> SingletonHList<_1Prime> flatMap(Fn1 SingletonHList<_1Prime> trampolineM( + Fn1, SingletonHList>> fn) { + return fmap(trampoline(head -> fn.apply(head).>>coerce().head())); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java index 648b82ee6..36a195011 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java @@ -9,6 +9,7 @@ import testsupport.traits.BifunctorLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.These.a; @@ -21,7 +22,12 @@ @RunWith(Traits.class) public class TheseTest { - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class, BifunctorLaws.class}) + @TestTraits({FunctorLaws.class, + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + TraversableLaws.class, + BifunctorLaws.class}) public Subjects> testSubject() { return subjects(a("foo"), b(1), both("foo", 1)); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java index fac2a7149..57a9f85b7 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java @@ -8,6 +8,7 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; import static com.jnape.palatable.lambda.adt.hlist.HList.nil; @@ -25,7 +26,7 @@ public void setUp() { singletonHList = new SingletonHList<>(1); } - @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class, MonadRecLaws.class}) public SingletonHList testSubject() { return singletonHList("one"); } From a74b98447ff11b1cfc497cce5f038a110cac5438 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 17 Sep 2019 11:49:36 -0500 Subject: [PATCH 253/348] Removing various unchecked warnings --- .../jnape/palatable/lambda/adt/Either.java | 6 ++++-- .../com/jnape/palatable/lambda/adt/These.java | 16 ++++++++------- .../palatable/lambda/adt/choice/Choice2.java | 3 +-- .../palatable/lambda/adt/choice/Choice3.java | 8 ++++---- .../palatable/lambda/adt/choice/Choice4.java | 10 +++++----- .../palatable/lambda/adt/choice/Choice5.java | 12 +++++------ .../palatable/lambda/adt/choice/Choice6.java | 20 +++++++++---------- .../palatable/lambda/adt/choice/Choice7.java | 16 +++++++-------- .../palatable/lambda/adt/choice/Choice8.java | 20 +++++++++---------- .../palatable/lambda/adt/hlist/Tuple2.java | 6 ++---- .../palatable/lambda/adt/hlist/Tuple3.java | 9 +++------ .../palatable/lambda/adt/hlist/Tuple5.java | 6 ++---- .../palatable/lambda/adt/hlist/Tuple6.java | 6 ++---- .../palatable/lambda/adt/hlist/Tuple7.java | 6 ++---- .../palatable/lambda/adt/hlist/Tuple8.java | 6 ++---- .../jnape/palatable/lambda/adt/hmap/HMap.java | 4 ++-- .../lambda/functions/specialized/Lift.java | 5 +++-- .../lambda/functions/specialized/Pure.java | 4 +++- .../lambda/functor/builtin/Const.java | 3 +-- .../functions/builtin/fn1/MagnetizeTest.java | 1 - .../testsupport/traits/EquivalenceTrait.java | 4 ++-- 21 files changed, 80 insertions(+), 91 deletions(-) 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 0734b413b..a26b6a42e 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/Either.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/Either.java @@ -10,6 +10,7 @@ import com.jnape.palatable.lambda.functions.specialized.SideEffect; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; +import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.lambda.monad.Monad; @@ -320,11 +321,12 @@ public Either catchError(Fn1>> * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public final , TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { - return (AppTrav) match(l -> pure.apply((TravB) left(l)), r -> fn.apply(r).fmap(Either::right)); + return match(l -> pure.apply(Either.left(l).coerce()), + r -> fn.apply(r).>fmap(Either::right).fmap(Functor::coerce)) + .coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index 6daad22dc..6721d33e8 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -85,13 +85,12 @@ public final These pure(C c) { * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") - public , TravB extends Traversable>, - AppTrav extends Applicative> - AppTrav traverse(Fn1> fn, Fn1 pure) { - return match(a -> pure.apply((TravB) a(a)), - b -> fn.apply(b).fmap(this::pure).fmap(Applicative::coerce).coerce(), - into((a, b) -> fn.apply(b).fmap(c -> both(a, c)).fmap(Applicative::coerce).coerce())); + public , TravC extends Traversable>, + AppTrav extends Applicative> + AppTrav traverse(Fn1> fn, Fn1 pure) { + return match(a -> pure.apply(These.a(a).coerce()), + b -> fn.apply(b).fmap(this::pure).fmap(Applicative::coerce).coerce(), + into((a, b) -> fn.apply(b).fmap(c -> both(a, c)).fmap(Applicative::coerce).coerce())); } /** @@ -126,6 +125,9 @@ public final These zip(Applicative, These< return MonadRec.super.zip(appFn).coerce(); } + /** + * {@inheritDoc} + */ @Override public Lazy> lazyZip( Lazy, These>> lazyAppFn) { diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java index 460e1fa40..067762f16 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice2.java @@ -165,11 +165,10 @@ public Choice2 trampolineM(Fn1, TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { - return match(a -> pure.apply((TravB) a(a)), + return match(a -> pure.apply(Choice2.a(a).coerce()), b -> fn.apply(b).>fmap(Choice2::b).fmap(Functor::coerce).coerce()); } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java index 86b836068..8116344e5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice3.java @@ -167,13 +167,13 @@ public Choice3 trampolineM( * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { - return match(a -> pure.apply((TravB) Choice3.a(a)).coerce(), - b -> pure.apply((TravB) Choice3.b(b)).coerce(), - c -> fn.apply(c).>fmap(Choice3::c).fmap(Functor::coerce).coerce()); + return match(a -> pure.apply(Choice3.a(a).coerce()), + b -> pure.apply(Choice3.b(b).coerce()), + c -> fn.apply(c).>fmap(Choice3::c).fmap(Functor::coerce)) + .coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java index d35fd3756..7f5afb2e6 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice4.java @@ -171,14 +171,14 @@ public Choice4 trampolineM( * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { - return match(a -> pure.apply((TravB) Choice4.a(a)).coerce(), - b -> pure.apply((TravB) Choice4.b(b)).coerce(), - c -> pure.apply((TravB) Choice4.c(c)), - d -> fn.apply(d).>fmap(Choice4::d).fmap(Functor::coerce).coerce()); + return match(a -> pure.apply(Choice4.a(a).coerce()), + b -> pure.apply(Choice4.b(b).coerce()), + c -> pure.apply(Choice4.c(c).coerce()), + d -> fn.apply(d).>fmap(Choice4::d).fmap(Functor::coerce)) + .coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java index 251f7a6c6..4a085c94a 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice5.java @@ -173,16 +173,16 @@ public Choice5 trampolineM( * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { - return match(a -> pure.apply((TravB) Choice5.a(a)).coerce(), - b -> pure.apply((TravB) Choice5.b(b)).coerce(), - c -> pure.apply((TravB) Choice5.c(c)), - d -> pure.apply((TravB) Choice5.d(d)), + return match(a -> pure.apply(Choice5.a(a).coerce()), + b -> pure.apply(Choice5.b(b).coerce()), + c -> pure.apply(Choice5.c(c).coerce()), + d -> pure.apply(Choice5.d(d).coerce()), e -> fn.apply(e).>fmap(Choice5::e) - .fmap(Applicative::coerce).coerce()); + .fmap(Applicative::coerce)) + .coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java index b87de1a97..ec0eacfc5 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice6.java @@ -82,18 +82,16 @@ public Choice6 fmap(Fn1 fn) { * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public Choice6 biMapL(Fn1 fn) { - return (Choice6) Bifunctor.super.biMapL(fn); + return (Choice6) Bifunctor.super.biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public Choice6 biMapR(Fn1 fn) { - return (Choice6) Bifunctor.super.biMapR(fn); + return (Choice6) Bifunctor.super.biMapR(fn); } /** @@ -179,17 +177,17 @@ public Choice6 trampolineM( * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { - return match(a -> pure.apply((TravB) Choice6.a(a)).coerce(), - b -> pure.apply((TravB) Choice6.b(b)).coerce(), - c -> pure.apply((TravB) Choice6.c(c)), - d -> pure.apply((TravB) Choice6.d(d)), - e -> pure.apply((TravB) Choice6.e(e)), + return match(a -> pure.apply(Choice6.a(a).coerce()), + b -> pure.apply(Choice6.b(b).coerce()), + c -> pure.apply(Choice6.c(c).coerce()), + d -> pure.apply(Choice6.d(d).coerce()), + e -> pure.apply(Choice6.e(e).coerce()), f -> fn.apply(f).>fmap(Choice6::f) - .fmap(Applicative::coerce).coerce()); + .fmap(Applicative::coerce)) + .coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java index 8561ea105..bf0131e84 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice7.java @@ -182,18 +182,18 @@ public Choice7 trampolineM( * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { - return match(a -> pure.apply((TravB) Choice7.a(a)).coerce(), - b -> pure.apply((TravB) Choice7.b(b)).coerce(), - c -> pure.apply((TravB) Choice7.c(c)), - d -> pure.apply((TravB) Choice7.d(d)), - e -> pure.apply((TravB) Choice7.e(e)), - f -> pure.apply((TravB) Choice7.f(f)), + return match(a -> pure.apply(Choice7.a(a).coerce()), + b -> pure.apply(Choice7.b(b).coerce()), + c -> pure.apply(Choice7.c(c).coerce()), + d -> pure.apply(Choice7.d(d).coerce()), + e -> pure.apply(Choice7.e(e).coerce()), + f -> pure.apply(Choice7.f(f).coerce()), g -> fn.apply(g).>fmap(Choice7::g) - .fmap(Applicative::coerce).coerce()); + .fmap(Applicative::coerce)) + .coerce(); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java index cc050a90c..edd220a7d 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/choice/Choice8.java @@ -6,8 +6,8 @@ import com.jnape.palatable.lambda.adt.hlist.HList; import com.jnape.palatable.lambda.adt.hlist.Tuple8; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.Bifunctor; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -177,19 +177,19 @@ public Choice8 trampolineM( * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public , TravB extends Traversable>, AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { - return match(a -> pure.apply((TravB) Choice8.a(a)).coerce(), - b -> pure.apply((TravB) Choice8.b(b)).coerce(), - c -> pure.apply((TravB) Choice8.c(c)), - d -> pure.apply((TravB) Choice8.d(d)), - e -> pure.apply((TravB) Choice8.e(e)), - f -> pure.apply((TravB) Choice8.f(f)), - g -> pure.apply((TravB) Choice8.g(g)), + return match(a -> pure.apply(Choice8.a(a).coerce()), + b -> pure.apply(Choice8.b(b).coerce()), + c -> pure.apply(Choice8.c(c).coerce()), + d -> pure.apply(Choice8.d(d).coerce()), + e -> pure.apply(Choice8.e(e).coerce()), + f -> pure.apply(Choice8.f(f).coerce()), + g -> pure.apply(Choice8.g(g).coerce()), h -> fn.apply(h).>fmap(Choice8::h) - .fmap(Applicative::coerce).coerce()); + .fmap(Applicative::coerce)) + .coerce(); } /** 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 2f59fb7e7..726335f6d 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 @@ -135,18 +135,16 @@ public <_2Prime> Tuple2<_1, _2Prime> fmap(Fn1 fn) * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public <_1Prime> Tuple2<_1Prime, _2> biMapL(Fn1 fn) { - return (Tuple2<_1Prime, _2>) Bifunctor.super.biMapL(fn); + return (Tuple2<_1Prime, _2>) Bifunctor.super.<_1Prime>biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public <_2Prime> Tuple2<_1, _2Prime> biMapR(Fn1 fn) { - return (Tuple2<_1, _2Prime>) Bifunctor.super.biMapR(fn); + return (Tuple2<_1, _2Prime>) Bifunctor.super.<_2Prime>biMapR(fn); } /** 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 f84af1061..e32eac589 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 @@ -108,27 +108,24 @@ public Tuple3<_2, _1, _3> invert() { * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public <_3Prime> Tuple3<_1, _2, _3Prime> fmap(Fn1 fn) { - return (Tuple3<_1, _2, _3Prime>) MonadRec.super.fmap(fn); + return (Tuple3<_1, _2, _3Prime>) MonadRec.super.<_3Prime>fmap(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public <_2Prime> Tuple3<_1, _2Prime, _3> biMapL(Fn1 fn) { - return (Tuple3<_1, _2Prime, _3>) Bifunctor.super.biMapL(fn); + return (Tuple3<_1, _2Prime, _3>) Bifunctor.super.<_2Prime>biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public <_3Prime> Tuple3<_1, _2, _3Prime> biMapR(Fn1 fn) { - return (Tuple3<_1, _2, _3Prime>) Bifunctor.super.biMapR(fn); + return (Tuple3<_1, _2, _3Prime>) Bifunctor.super.<_3Prime>biMapR(fn); } /** 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 3c9e4e941..c87ee564b 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 @@ -170,18 +170,16 @@ public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> fmap(Fn1 Tuple5<_1, _2, _3, _4Prime, _5> biMapL(Fn1 fn) { - return (Tuple5<_1, _2, _3, _4Prime, _5>) Bifunctor.super.biMapL(fn); + return (Tuple5<_1, _2, _3, _4Prime, _5>) Bifunctor.super.<_4Prime>biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public <_5Prime> Tuple5<_1, _2, _3, _4, _5Prime> biMapR(Fn1 fn) { - return (Tuple5<_1, _2, _3, _4, _5Prime>) Bifunctor.super.biMapR(fn); + return (Tuple5<_1, _2, _3, _4, _5Prime>) Bifunctor.super.<_5Prime>biMapR(fn); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index e7d21dcff..6d07b503b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -198,18 +198,16 @@ public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> fmap(Fn1 Tuple6<_1, _2, _3, _4, _5Prime, _6> biMapL(Fn1 fn) { - return (Tuple6<_1, _2, _3, _4, _5Prime, _6>) Bifunctor.super.biMapL(fn); + return (Tuple6<_1, _2, _3, _4, _5Prime, _6>) Bifunctor.super.<_5Prime>biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public <_6Prime> Tuple6<_1, _2, _3, _4, _5, _6Prime> biMapR(Fn1 fn) { - return (Tuple6<_1, _2, _3, _4, _5, _6Prime>) Bifunctor.super.biMapR(fn); + return (Tuple6<_1, _2, _3, _4, _5, _6Prime>) Bifunctor.super.<_6Prime>biMapR(fn); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index c65cda76a..a3e162f73 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -226,18 +226,16 @@ public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> fmap(Fn1 Tuple7<_1, _2, _3, _4, _5, _6Prime, _7> biMapL(Fn1 fn) { - return (Tuple7<_1, _2, _3, _4, _5, _6Prime, _7>) Bifunctor.super.biMapL(fn); + return (Tuple7<_1, _2, _3, _4, _5, _6Prime, _7>) Bifunctor.super.<_6Prime>biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public <_7Prime> Tuple7<_1, _2, _3, _4, _5, _6, _7Prime> biMapR(Fn1 fn) { - return (Tuple7<_1, _2, _3, _4, _5, _6, _7Prime>) Bifunctor.super.biMapR(fn); + return (Tuple7<_1, _2, _3, _4, _5, _6, _7Prime>) Bifunctor.super.<_7Prime>biMapR(fn); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 21ca92738..8a8001e24 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -254,18 +254,16 @@ public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> fmap(Fn1 Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8> biMapL(Fn1 fn) { - return (Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8>) Bifunctor.super.biMapL(fn); + return (Tuple8<_1, _2, _3, _4, _5, _6, _7Prime, _8>) Bifunctor.super.<_7Prime>biMapL(fn); } /** * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public <_8Prime> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime> biMapR(Fn1 fn) { - return (Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime>) Bifunctor.super.biMapR(fn); + return (Tuple8<_1, _2, _3, _4, _5, _6, _7, _8Prime>) Bifunctor.super.<_8Prime>biMapR(fn); } /** 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 bf3362d77..62c922ece 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 @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.builtin.fn1.Downcast; import java.util.ArrayList; import java.util.Collection; @@ -45,9 +46,8 @@ private HMap(Map, Object> table) { * @param the value type * @return Maybe the value at this key */ - @SuppressWarnings("unchecked") public Maybe get(TypeSafeKey key) { - return maybe((A) table.get(key)).fmap(view(key)); + return maybe(Downcast.downcast(table.get(key))).fmap(view(key)); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java index acd35e10f..1620fac7c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Lift.java @@ -4,6 +4,8 @@ import com.jnape.palatable.lambda.monad.MonadBase; import com.jnape.palatable.lambda.monad.MonadRec; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; + /** * Generalized, portable lifting operation for lifting a {@link MonadRec} into a {@link MonadBase}. * @@ -17,8 +19,7 @@ > MonadBase checkedApply(MonadRec ga) default , MBA extends MonadBase> MBA apply(MonadRec ma) { try { - @SuppressWarnings("unchecked") MBA MBA = (MBA) checkedApply(ma); - return MBA; + return downcast(checkedApply(ma)); } catch (Throwable t) { throw Runtime.throwChecked(t); } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java index 4e8737cd7..797a2e8aa 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/Pure.java @@ -4,6 +4,8 @@ import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.internal.Runtime; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; + /** * Generalized, portable {@link Applicative#pure(Object)}, with a loosened {@link Functor} constraint. * @@ -16,7 +18,7 @@ public interface Pure> { default > FA apply(A a) { try { - @SuppressWarnings("unchecked") FA fa = (FA) checkedApply(a); + @SuppressWarnings("unchecked") FA fa = downcast(checkedApply(a)); return fa; } catch (Throwable t) { throw Runtime.throwChecked(t); diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java index a44417bed..dfc29b1c6 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Const.java @@ -135,9 +135,8 @@ public Const biMapL(Fn1 fn) { * {@inheritDoc} */ @Override - @SuppressWarnings("unchecked") public Const biMapR(Fn1 fn) { - return (Const) Bifunctor.super.biMapR(fn); + return (Const) Bifunctor.super.biMapR(fn); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/MagnetizeTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/MagnetizeTest.java index 87f5a983e..cec328d11 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/MagnetizeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/MagnetizeTest.java @@ -26,7 +26,6 @@ public Fn1, Iterable>> testSubject() { } @Test - @SuppressWarnings("unchecked") public void magnetizesElementsByPredicateOutcome() { assertThat(magnetize(asList(1, 1, 2, 3, 3, 3, 2, 2, 1)), contains(iterates(1, 1), diff --git a/src/test/java/testsupport/traits/EquivalenceTrait.java b/src/test/java/testsupport/traits/EquivalenceTrait.java index 1c83ddb8e..6ac3dbee5 100644 --- a/src/test/java/testsupport/traits/EquivalenceTrait.java +++ b/src/test/java/testsupport/traits/EquivalenceTrait.java @@ -2,6 +2,7 @@ import com.jnape.palatable.traitor.traits.Trait; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Downcast.downcast; import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static testsupport.traits.Equivalence.equivalence; @@ -27,7 +28,6 @@ default void test(Object value) { if (!type.isInstance(value)) throw new ClassCastException("Unable to create " + type.getSimpleName() + " surrogate for value of type " + value.getClass().getSimpleName()); - @SuppressWarnings("unchecked") A b = (A) value; - test(equivalence(b, id())); + test(equivalence(downcast(value), id())); } } From c413e1805fb4a0d55d158bdd620a5525ff4bdc83 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 20 Sep 2019 15:11:03 -0500 Subject: [PATCH 254/348] Tightening up CHANGELOG --- CHANGELOG.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eabfad889..dea2713de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Changed - ***Breaking Change***: `MonadT` is now witnessed by a parameter for better subtyping, and no longer requires a common - `run` interface + `run` interface; each `run` method is now `runXXXT()`, where `XXX` is the name of the transformer in question - ***Breaking Change***: `Applicative#zip` and derivatives evaluate from left to right now across the board. - ***Breaking Change***: `testsupport.EquatableM` replaced with `Equivalence` - `Alter` now merely requires an `Fn1` instead of an explicit `Effect` @@ -15,31 +15,32 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). retain parallelization inflection points ### Added -- `MonadError`, monads that can be thrown to and caught from, with defaults for `IO`, `Either`, `Maybe`, and `Try` - `MonadRec`, monads that support a stack-safe `trampolineM` method with defaults for all exported monads -- `Optic#andThen`, `Optic#compose`, and other defaults added -- `Prism#andThen`, `Prism#compose` begets another `Prism` -- `Prism#fromPartial` public interfaces +- `MonadError`, monads that can be thrown to and caught from, with defaults for `IO`, `Either`, `Maybe`, and `Try` +- `MonadBase`, an interface representing lifting infrastructure for `Monad`s +- `MonadReader` and `MonadWriter`, general interfaces for reading from an environment and accumulating results +- `SafeT`, a stack-safe monad transformer for any `MonadRec` - `ReaderT`, the transformer for the reader monad -- `Until`, for repeatedly executing an `IO` until its result matches a predicate +- `WriterT`, a monad transformer for an accumulation and a value +- `StateT`, the `State` monad transformer +- `Lift`, an existentially-quantified lifting function for some `MonadBase` type - `IO#interruptible`, for wrapping an `IO` in a thread interruption check - `IO#monitorSync`, for wrapping an `IO` in a `synchronized` block on a given lock object - `IO#pin`, for pinning an `IO` to an `Executor` without yet executing it - `IO#fuse`, for fusing the fork opportunities of a given `IO` into a single linearized `IO` - `IO#memoize`, for memoizing an `IO` by caching its first successful result +- `Until`, for repeatedly executing an `IO` until its result matches a predicate +- `Optic#andThen`, `Optic#compose`, and other defaults added +- `Prism#andThen`, `Prism#compose` begets another `Prism` +- `Prism#fromPartial` public interfaces - `Tuple2-8#fromIterable`, for populating a `TupleN` with the first `N` elements of an `Iterable` - `Fn2#curry`, for converting an `Fn1,C>` to an `Fn2` -- `MonadBase`, an interface representing lifting infrastructure for `Monad`s -- `Lift`, an existentially-quantified lifting function for some `MonadBase` type -- `MonadReader` and `MonadWriter`, general interfaces for reading from an environment and accumulating results -- `StateT`, the `State` monad transformer -- `WriterT`, a monad transformer for an accumulation and a value - `EquivalenceTrait`, a traitor `Trait` to make it easier to test properties of type-classes with a separate equivalence relation -- `SafeT`, a stack-safe monad transformer for any `MonadRec` ### Deprecated - `Peek`, `Peek2`, `Maybe#peek`, and `Either#peek` in favor of explicitly matching into `IO` and running it +- `Force`, in favor if traversing into an `IO` and explicitly running it ## [4.0.0] - 2019-05-20 ### Changed From cee0bf6c36da9e60126b0b6475a747b455fe942a Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 20 Sep 2019 15:37:40 -0500 Subject: [PATCH 255/348] Adding IO#exceptionally deprecation notice --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dea2713de..b29aef81a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Deprecated - `Peek`, `Peek2`, `Maybe#peek`, and `Either#peek` in favor of explicitly matching into `IO` and running it - `Force`, in favor if traversing into an `IO` and explicitly running it +- `IO#exceptionally` in favor of `IO#catchError` (from `MonadError`) ## [4.0.0] - 2019-05-20 ### Changed From 02e350bd706784f665bf08d39e271a99e0bc41d7 Mon Sep 17 00:00:00 2001 From: Evan Bowling Date: Mon, 16 Sep 2019 23:32:01 -0500 Subject: [PATCH 256/348] Updating README examples --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index c56db81be..8e2641d63 100644 --- a/README.md +++ b/README.md @@ -75,22 +75,22 @@ compile group: 'com.jnape.palatable', name: 'lambda', version: '4.0.0' First, the obligatory `map`/`filter`/`reduce` example: ```Java -Integer sumOfEvenIncrements = +Maybe sumOfEvenIncrements = reduceLeft((x, y) -> x + y, filter(x -> x % 2 == 0, map(x -> x + 1, asList(1, 2, 3, 4, 5)))); -//-> 12 +//-> Just 12 ``` Every function in lambda is [curried](https://www.wikiwand.com/en/Currying), so we could have also done this: ```Java -Fn1, Integer> sumOfEvenIncrementsFn = +Fn1, Maybe> sumOfEvenIncrementsFn = map((Integer x) -> x + 1) - .andThen(filter(x -> x % 2 == 0)) - .andThen(reduceLeft((x, y) -> x + y)); + .fmap(filter(x -> x % 2 == 0)) + .fmap(reduceLeft((x, y) -> x + y)); -Integer sumOfEvenIncrements = sumOfEvenIncrementsFn.apply(asList(1, 2, 3, 4, 5)); -//-> 12 +Maybe sumOfEvenIncrements = sumOfEvenIncrementsFn.apply(asList(1, 2, 3, 4, 5)); +//-> Just 12 ``` How about the positive squares below 100: @@ -106,7 +106,7 @@ We could have also used `unfoldr`: ```Java Iterable positiveSquaresBelow100 = unfoldr(x -> { int square = x * x; - return square < 100 ? Optional.of(tuple(square, x + 1)) : Optional.empty(); + return square < 100 ? Maybe.just(tuple(square, x + 1)) : Maybe.nothing(); }, 1); //-> [1, 4, 9, 16, 25, 36, 49, 64, 81] ``` @@ -116,7 +116,7 @@ What if we want the cross product of a domain and codomain: ```Java Iterable> crossProduct = take(10, cartesianProduct(asList(1, 2, 3), asList("a", "b", "c"))); -//-> (1,"a"), (1,"b"), (1,"c"), (2,"a"), (2,"b"), (2,"c"), (3,"a"), (3,"b"), (3,"c") +//-> [(1,"a"), (1,"b"), (1,"c"), (2,"a"), (2,"b"), (2,"c"), (3,"a"), (3,"b"), (3,"c")] ``` Let's compose two functions: @@ -125,9 +125,9 @@ Let's compose two functions: Fn1 add = x -> x + 1; Fn1 subtract = x -> x -1; -Fn1 noOp = add.andThen(subtract); +Fn1 noOp = add.fmap(subtract); // same as -Fn1 alsoNoOp = subtract.compose(add); +Fn1 alsoNoOp = subtract.contraMap(add); ``` And partially apply some: @@ -144,7 +144,7 @@ And have fun with 3s: ```Java Iterable> multiplesOf3InGroupsOf3 = - take(3, inGroupsOf(3, unfoldr(x -> Optional.of(tuple(x * 3, x + 1)), 1))); + take(3, inGroupsOf(3, unfoldr(x -> Maybe.just(tuple(x * 3, x + 1)), 1))); //-> [[3, 6, 9], [12, 15, 18], [21, 24, 27]] ``` @@ -176,7 +176,7 @@ Check out the [semigroup](https://palatable.github.io/lambda/javadoc/com/jnape/p ```Java Monoid multiply = monoid((x, y) -> x * y, 1); -multiple.reduceLeft(emptyList()); //-> 1 +multiply.reduceLeft(emptyList()); //-> 1 multiply.reduceLeft(asList(1, 2, 3)); //-> 6 multiply.foldMap(Integer::parseInt, asList("1", "2", "3")); //-> also 6 ``` From 026d16e79ca1be5c7281946f58fc4d1cb4df3663 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 23 Sep 2019 11:17:13 -0500 Subject: [PATCH 257/348] ReaderT#readerT should be public --- .../palatable/lambda/monad/transformer/builtin/ReaderT.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index 1cc9f511e..2af18e16d 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -201,7 +201,8 @@ public ReaderT> carry() { * @param the embedded output type * @return the {@link ReaderT} */ - static , A> ReaderT readerT(Fn1> fn) { + public static , A> ReaderT readerT( + Fn1> fn) { return new ReaderT<>(fn); } From f4d644d5ac2361c6c199f7f3fbc8ed68d8cfe595 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 23 Sep 2019 11:40:07 -0500 Subject: [PATCH 258/348] [maven-release-plugin] prepare release lambda-5.0.0 --- pom.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index c11f99dde..c767905b6 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 @@ -10,7 +9,7 @@ lambda - 4.0.1-SNAPSHOT + 5.0.0 jar Lambda From 52ec2376ae333bf378e53bd10370bdc0f04f8366 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 23 Sep 2019 11:40:14 -0500 Subject: [PATCH 259/348] [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 c767905b6..aca3bad76 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.0.0 + 5.0.1-SNAPSHOT jar Lambda From 67750c7510f5a005acc57ed32a09fa77472e72e1 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 23 Sep 2019 13:59:57 -0500 Subject: [PATCH 260/348] Updating README and CHANGELOG --- CHANGELOG.md | 6 +++++- README.md | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b29aef81a..28169cd3c 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 changes yet + +## [5.0.0] - 2019-09-23 ### Changed - ***Breaking Change***: `MonadT` is now witnessed by a parameter for better subtyping, and no longer requires a common `run` interface; each `run` method is now `runXXXT()`, where `XXX` is the name of the transformer in question @@ -525,7 +528,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-4.0.0...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-5.0.0...HEAD +[5.0.0]: https://github.com/palatable/lambda/compare/lambda-4.0.0...lambda-5.0.0 [4.0.0]: https://github.com/palatable/lambda/compare/lambda-3.3.0...lambda-4.0.0 [3.3.0]: https://github.com/palatable/lambda/compare/lambda-3.2.0...lambda-3.3.0 [3.2.0]: https://github.com/palatable/lambda/compare/lambda-3.1.0...lambda-3.2.0 diff --git a/README.md b/README.md index 8e2641d63..be008c911 100644 --- a/README.md +++ b/README.md @@ -60,14 +60,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 4.0.0 + 5.0.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '4.0.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '5.0.0' ``` Examples From ade8610ae1aa1602af72d9aad725d1f627f98f67 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 28 Sep 2019 17:18:14 -0500 Subject: [PATCH 261/348] Adding the Writer monad --- CHANGELOG.md | 3 +- .../lambda/functor/builtin/Writer.java | 182 ++++++++++++++++++ .../monad/transformer/builtin/WriterT.java | 11 +- .../lambda/functor/builtin/WriterTest.java | 44 +++++ .../transformer/builtin/WriterTTest.java | 4 - 5 files changed, 234 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functor/builtin/Writer.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functor/builtin/WriterTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 28169cd3c..f1b2010dc 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 changes yet +### Added +- `Writer`, the writer monad ## [5.0.0] - 2019-09-23 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Writer.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Writer.java new file mode 100644 index 000000000..bb00cb402 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Writer.java @@ -0,0 +1,182 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.MonadWriter; +import com.jnape.palatable.lambda.monad.transformer.builtin.WriterT; +import com.jnape.palatable.lambda.monoid.Monoid; + +import static com.jnape.palatable.lambda.adt.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Both.both; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.recursion.Trampoline.trampoline; + +/** + * The lazy writer monad, a monad capturing some accumulation (eventually to be folded in terms of a given monoid) and + * a value. Note that unlike the {@link State} monad, the {@link Writer} monad does not allow the value to be fully + * derived from the accumulation. + * + * @param the accumulation type + * @param the value type + */ +public final class Writer implements + MonadWriter>, + MonadRec> { + + private final Fn1, ? extends Tuple2> writerFn; + + private Writer(Fn1, ? extends Tuple2> writerFn) { + this.writerFn = writerFn; + } + + /** + * Given a {@link Monoid} for the accumulation, run the computation represented by this {@link Writer}, accumulate + * the written output in terms of the {@link Monoid}, and produce the accumulation and the value. + * + * @param monoid the accumulation {@link Monoid} + * @return the accumulation with the value + */ + public Tuple2 runWriter(Monoid monoid) { + return writerFn.apply(monoid); + } + + /** + * {@inheritDoc} + */ + @Override + public Writer> listens(Fn1 fn) { + return new Writer<>(monoid -> runWriter(monoid).into((a, w) -> tuple(both(constantly(a), fn, w), w))); + } + + /** + * {@inheritDoc} + */ + @Override + public Writer censor(Fn1 fn) { + return new Writer<>(monoid -> runWriter(monoid).fmap(fn)); + } + + /** + * {@inheritDoc} + */ + @Override + public Writer trampolineM(Fn1, Writer>> fn) { + return new Writer<>(monoid -> trampoline(into((a, w) -> fn.apply(a).>>coerce() + .runWriter(monoid) + .fmap(monoid.apply(w)) + .into((aOrB, w_) -> aOrB.biMap(a_ -> tuple(a_, w_), b -> tuple(b, w_)))), runWriter(monoid))); + } + + /** + * {@inheritDoc} + */ + @Override + public Writer flatMap(Fn1>> f) { + return new Writer<>(monoid -> writerFn.apply(monoid) + .into((a, w) -> f.apply(a).>coerce().runWriter(monoid).fmap(monoid.apply(w)))); + } + + /** + * {@inheritDoc} + */ + @Override + public Writer pure(B b) { + return listen(b); + } + + /** + * {@inheritDoc} + */ + @Override + public Writer fmap(Fn1 fn) { + return MonadRec.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Writer zip(Applicative, Writer> appFn) { + return MonadRec.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, Writer>> lazyAppFn) { + return MonadRec.super.lazyZip(lazyAppFn).fmap(MonadRec>::coerce); + } + + /** + * {@inheritDoc} + */ + @Override + public Writer discardL(Applicative> appB) { + return MonadRec.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Writer discardR(Applicative> appB) { + return MonadRec.super.discardR(appB).coerce(); + } + + /** + * Construct a {@link Writer} from an accumulation. + * + * @param the accumulation type + * @return the {@link Writer} + */ + public static Writer tell(W w) { + return writer(tuple(UNIT, w)); + } + + /** + * Construct a {@link Writer} from a value. + * + * @param the accumulation type + * @param the value type + * @return the {@link Writer} + */ + public static Writer listen(A a) { + return Writer.pureWriter().apply(a); + } + + /** + * Construct a {@link Writer} from an accumulation and a value. + * + * @param the accumulation type + * @param the value type + * @return the {@link WriterT} + */ + public static Writer writer(Tuple2 aw) { + return new Writer<>(constantly(aw)); + } + + /** + * The canonical {@link Pure} instance for {@link Writer}. + * + * @param the accumulation type + * @return the {@link Pure} instance + */ + public static Pure> pureWriter() { + return new Pure>() { + @Override + public Writer checkedApply(A a) { + return new Writer<>(monoid -> tuple(a, monoid.identity())); + } + }; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java index da80ad984..aae118a15 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java @@ -8,6 +8,7 @@ import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.functor.builtin.Writer; import com.jnape.palatable.lambda.monad.Monad; import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.MonadWriter; @@ -23,7 +24,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; /** - * A strict transformer for a {@link Tuple2} holding a value and an accumulation. + * A {@link MonadT monad transformer} for {@link Writer}. * * @param the accumulation type * @param the {@link Monad monadic embedding} @@ -177,14 +178,14 @@ public static , A> WriterT listen(MonadRec< /** * Lift a value and an accumulation embedded in a {@link Monad} into a {@link WriterT}. * - * @param mwa the value and accumulation inside a {@link Monad} + * @param maw the value and accumulation inside a {@link Monad} * @param the accumulation type * @param the {@link Monad} type * @param the value type * @return the {@link WriterT} */ - public static , A> WriterT writerT(MonadRec, M> mwa) { - return new WriterT<>(constantly(mwa)); + public static , A> WriterT writerT(MonadRec, M> maw) { + return new WriterT<>(constantly(maw)); } /** @@ -198,7 +199,7 @@ public static , A> WriterT writerT(MonadRec public static > Pure> pureWriterT(Pure pureM) { return new Pure>() { @Override - public WriterT checkedApply(A a) throws Throwable { + public WriterT checkedApply(A a) { return listen(pureM.>apply(a)); } }; diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/WriterTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/WriterTest.java new file mode 100644 index 000000000..62c29d33e --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/WriterTest.java @@ -0,0 +1,44 @@ +package com.jnape.palatable.lambda.functor.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; +import testsupport.traits.MonadWriterLaws; + +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functor.builtin.Writer.listen; +import static com.jnape.palatable.lambda.functor.builtin.Writer.tell; +import static com.jnape.palatable.lambda.functor.builtin.Writer.writer; +import static com.jnape.palatable.lambda.monoid.builtin.Join.join; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static org.junit.Assert.assertEquals; +import static testsupport.traits.Equivalence.equivalence; + +@RunWith(Traits.class) +public class WriterTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class, MonadWriterLaws.class}) + public Subjects>> testSubject() { + Fn1, Object> runWriter = w -> w.runWriter(join()); + return subjects(equivalence(tell("foo"), runWriter), + equivalence(listen(1), runWriter), + equivalence(writer(tuple(1, "foo")), runWriter)); + } + + @Test + public void tellListenInteraction() { + assertEquals(tuple(1, "hello, world!"), + tell("hello, ") + .discardL(listen(1)) + .discardR(tell("world!")) + .runWriter(join())); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java index a1e3f0531..e0017a20a 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java @@ -1,6 +1,5 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; -import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -14,11 +13,8 @@ import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadWriterLaws; -import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -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.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.monad.transformer.builtin.WriterT.writerT; import static com.jnape.palatable.lambda.monoid.builtin.Join.join; From 9d115e50b5c59bea8cd5259a5508ea966d6aa663 Mon Sep 17 00:00:00 2001 From: Oren Miller Date: Sat, 12 Oct 2019 10:04:10 -0500 Subject: [PATCH 262/348] Adding AutoBracket, an AutoClosable constrained Bracket --- .../functions/builtin/fn2/AutoBracket.java | 48 +++++++++++++++++++ .../builtin/fn2/AutoBracketTest.java | 48 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/AutoBracket.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AutoBracketTest.java diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/AutoBracket.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/AutoBracket.java new file mode 100644 index 000000000..cf5108bbb --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/AutoBracket.java @@ -0,0 +1,48 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.builtin.fn3.Bracket; +import com.jnape.palatable.lambda.io.IO; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Bracket.bracket; +import static com.jnape.palatable.lambda.io.IO.io; + +/** + * Given an {@link IO} yielding some {@link AutoCloseable} type A and a kleisli arrow from that type to a + * new {@link IO} of type B, attempt to provision the A, applying the body operation if + * provisioning was successful and ensuring that {@link AutoCloseable#close} is called regardless of whether the body + * succeeds or fails. + *

+ * This is the canonical {@link Bracket bracketing} operation for {@link AutoCloseable AutoCloseables}. + * + * @param the initial {@link AutoCloseable} value type to map and clean up + * @param the resulting type + * @see Bracket + */ +public final class AutoBracket implements + Fn2, Fn1>, IO> { + + private static final AutoBracket INSTANCE = new AutoBracket<>(); + + private AutoBracket() { + } + + @Override + public IO checkedApply(IO io, Fn1> bodyIO) { + return bracket(io, a -> io(a::close), bodyIO); + } + + @SuppressWarnings("unchecked") + public static AutoBracket autoBracket() { + return (AutoBracket) INSTANCE; + } + + public static Fn1>, IO> autoBracket(IO io) { + return AutoBracket.autoBracket().apply(io); + } + + public static IO autoBracket(IO io, Fn1> bodyIO) { + return AutoBracket.autoBracket(io).apply(bodyIO); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AutoBracketTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AutoBracketTest.java new file mode 100644 index 000000000..b6cd3cf4a --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AutoBracketTest.java @@ -0,0 +1,48 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.io.IO; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicInteger; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.AutoBracket.autoBracket; +import static com.jnape.palatable.lambda.io.IO.io; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.IOMatcher.throwsException; +import static testsupport.matchers.IOMatcher.yieldsValue; + +public class AutoBracketTest { + + private AtomicInteger closedCounter; + private AutoCloseable autoCloseable; + + @Before + public void setUp() { + closedCounter = new AtomicInteger(0); + autoCloseable = closedCounter::incrementAndGet; + } + + @Test + public void closeWhenDone() { + IO bracketed = autoBracket(io(autoCloseable), closeable -> io(1)); + + assertEquals(0, closedCounter.get()); + assertThat(bracketed, yieldsValue(equalTo(1))); + assertEquals(1, closedCounter.get()); + } + + @Test + public void closeOnException() { + RuntimeException cause = new RuntimeException(); + + IO bracketed = autoBracket(io(autoCloseable), closeable -> IO.throwing(cause)); + + assertEquals(0, closedCounter.get()); + assertThat(bracketed, throwsException(equalTo(cause))); + assertEquals(1, closedCounter.get()); + } +} \ No newline at end of file From 79bd9280157277d5b1449d342318ff3173695412 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 5 Oct 2019 17:19:07 -0500 Subject: [PATCH 263/348] SafeT#zip is stack-safe, but does not rely on delegate monad's zip --- .../jnape/palatable/lambda/monad/SafeT.java | 13 ++------ .../palatable/lambda/monad/SafeTTest.java | 31 ++++--------------- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/SafeT.java b/src/main/java/com/jnape/palatable/lambda/monad/SafeT.java index 9eada32da..6266cdfef 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/SafeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/SafeT.java @@ -90,16 +90,7 @@ public SafeT flatMap(Fn1>> f */ @Override public SafeT zip(Applicative, SafeT> appFn) { - return body.resume() - .match(mBodyA -> appFn.>>coerce().body.resume() - .match(mBodyF -> new SafeT<>(Body.more(mBodyA.zip(mBodyF.fmap( - bodyF -> bodyA -> new SafeT<>(bodyA, pureM).zip(new SafeT<>(bodyF, pureM)).body))), pureM), - f -> new SafeT<>(Body.more(mBodyA.fmap(b -> Body.suspend( - b, a -> Body.done(f.apply(a))))), pureM)), - a -> appFn.>>coerce().body.resume() - .match(mBodyF -> new SafeT<>(new Body.More<>(mBodyF.fmap( - body -> new SafeT<>(body, pureM).fmap(f -> f.apply(a)).body)), pureM), - f -> pure(f.apply(a)))); + return MonadT.super.zip(appFn).coerce(); } /** @@ -153,7 +144,7 @@ public SafeT trampolineM(Fn1, A> SafeT safeT(MonadRec ma) { - return new SafeT<>(new Body.More<>(ma.fmap(Body.Done::new)), Pure.of(ma)); + return new SafeT<>(Body.more(ma.fmap(Body::done)), Pure.of(ma)); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/monad/SafeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/SafeTTest.java index 17206c5fa..9aa64f722 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/SafeTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/SafeTTest.java @@ -1,10 +1,8 @@ package com.jnape.palatable.lambda.monad; -import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.builtin.fn1.Id; import com.jnape.palatable.lambda.functor.builtin.Identity; -import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -15,12 +13,9 @@ import testsupport.traits.MonadLaws; import testsupport.traits.MonadRecLaws; -import java.util.concurrent.CountDownLatch; - +import static com.jnape.palatable.lambda.functions.Fn1.fn1; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; -import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monad.SafeT.safeT; -import static java.util.concurrent.Executors.newFixedThreadPool; import static org.junit.Assert.assertEquals; import static testsupport.Constants.STACK_EXPLODING_NUMBER; import static testsupport.traits.Equivalence.equivalence; @@ -52,25 +47,11 @@ public void flatMapStackSafety() { @Test public void zipStackSafety() { - assertEquals(new Identity<>(STACK_EXPLODING_NUMBER), + assertEquals((Integer) (STACK_EXPLODING_NUMBER + 1), times(STACK_EXPLODING_NUMBER, - safeT -> safeT.zip(safeT(new Identity<>(x -> x + 1))), - safeT(new Identity<>(0))).runSafeT()); - - } - - @Test(timeout = 500) - public void compositionallyPreservesZip() { - CountDownLatch latch = new CountDownLatch(2); - IO countDownAndAwait = io(() -> { - latch.countDown(); - latch.await(); - }); - - safeT(countDownAndAwait) - .discardL(safeT(countDownAndAwait)) - .>runSafeT() - .unsafePerformAsyncIO(newFixedThreadPool(2)) - .join(); + safeT -> safeT.zip(safeT(fn1(x -> y -> x + y))), + safeT(Fn1.fn1(x -> x))) + .>runSafeT() + .apply(1)); } } \ No newline at end of file From 435f3a5a4b8f05ed80981c86ad0f0d2302fca24e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 29 Sep 2019 17:23:21 -0500 Subject: [PATCH 264/348] Adding EndoK monoid --- CHANGELOG.md | 1 + .../lambda/monoid/builtin/EndoK.java | 59 +++++++++++++++++++ .../lambda/monoid/builtin/EndoKTest.java | 34 +++++++++++ 3 files changed, 94 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monoid/builtin/EndoK.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monoid/builtin/EndoKTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f1b2010dc..b68b98fdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] ### Added - `Writer`, the writer monad +- `EndoK`, a monoid formed under endomorphism for any monad ## [5.0.0] - 2019-09-23 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/EndoK.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/EndoK.java new file mode 100644 index 000000000..22dd6ba48 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/EndoK.java @@ -0,0 +1,59 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; +import com.jnape.palatable.lambda.functions.specialized.MonoidFactory; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.SafeT; +import com.jnape.palatable.lambda.monoid.Monoid; + +import static com.jnape.palatable.lambda.functions.specialized.Kleisli.kleisli; +import static com.jnape.palatable.lambda.monad.SafeT.safeT; + +/** + * The monoid formed under monadic endomorphism. + * + * @param the {@link MonadRec} witness + * @param the carrier type + * @param the fully witnessed {@link MonadRec} type + */ +public final class EndoK, A, MA extends MonadRec> implements + MonoidFactory, Fn1> { + + private static final EndoK INSTANCE = new EndoK<>(); + + @Override + public Monoid> checkedApply(Pure pureM) { + return new Monoid>() { + @Override + public Fn1 identity() { + return pureM::apply; + } + + @Override + public Fn1 checkedApply(Fn1 f, Fn1 g) { + return a -> kleisli(f).andThen(g::apply).apply(a); + } + + @Override + public Fn1 foldMap(Fn1> fn, Iterable bs) { + return a -> FoldLeft.foldLeft((f, b) -> f.fmap(ma -> ma.flatMap(a_ -> safeT(fn.apply(b).apply(a_)))), + safeT(identity()).fmap(SafeT::safeT), + bs) + .>>runSafeT() + .apply(a) + .runSafeT(); + } + }; + } + + @SuppressWarnings("unchecked") + public static , A, MA extends MonadRec> EndoK endoK() { + return (EndoK) INSTANCE; + } + + public static , A, MA extends MonadRec> Monoid> endoK(Pure pureM) { + return EndoK.endoK().apply(pureM); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/EndoKTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/EndoKTest.java new file mode 100644 index 000000000..64e51f86e --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/EndoKTest.java @@ -0,0 +1,34 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.monoid.Monoid; +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn2.Replicate.replicate; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; +import static com.jnape.palatable.lambda.monoid.builtin.EndoK.endoK; +import static org.junit.Assert.assertEquals; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; + +public class EndoKTest { + + @Test + public void identity() { + Monoid>> endoK = endoK(pureIdentity()); + assertEquals(new Identity<>(1), endoK.identity().apply(1)); + } + + @Test + public void monoid() { + Monoid>> endoK = endoK(pureIdentity()); + assertEquals(new Identity<>(3), + endoK.apply(x -> new Identity<>(x + 1), x -> new Identity<>(x + 2)).apply(0)); + } + + @Test + public void stackSafe() { + Monoid>> endoK = endoK(pureIdentity()); + assertEquals(new Identity<>(0), endoK.reduceLeft(replicate(STACK_EXPLODING_NUMBER, Identity::new)).apply(0)); + } +} \ No newline at end of file From b993936ea6ae872f460fe0d1832c168c8c9fced6 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 8 Oct 2019 16:59:22 -0500 Subject: [PATCH 265/348] StateT#zip preserves all state transformations --- .../monad/transformer/builtin/StateT.java | 6 +----- .../lambda/functor/builtin/StateTest.java | 2 +- .../monad/transformer/builtin/StateTTest.java | 20 ++++++++++++++----- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java index 907d71d51..071ce0dc5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java @@ -152,11 +152,7 @@ public StateT fmap(Fn1 fn) { */ @Override public StateT zip(Applicative, StateT> appFn) { - return stateT(s -> runStateT(s) - .zip(appFn.>>coerce() - .runStateT(s) - .fmap(Tuple2::_1) - .fmap(f -> t -> t.biMapL(f)))); + return MonadT.super.zip(appFn).coerce(); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java index fba168ecd..db591bcfa 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java @@ -12,8 +12,8 @@ import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; import testsupport.traits.MonadReaderLaws; -import testsupport.traits.MonadWriterLaws; import testsupport.traits.MonadRecLaws; +import testsupport.traits.MonadWriterLaws; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java index f36d660ef..b30fd4596 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -15,10 +16,16 @@ import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadWriterLaws; +import java.util.ArrayList; +import java.util.List; + import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.lenses.ListLens.elementAt; +import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static testsupport.traits.Equivalence.equivalence; @@ -57,11 +64,14 @@ public void mapStateT() { @Test public void zipping() { - assertEquals(new Identity<>(tuple(4, "final state: FOO")), - StateT.>modify(s -> new Identity<>(s.toUpperCase())) - .discardL(StateT.gets(s -> new Identity<>(s.length()))) - .flatMap(x -> StateT.stateT(s -> new Identity<>(tuple(x + 1, "final state: " + s)))) - .>>runStateT("foo")); + Tuple2> result = StateT., Identity>modify( + s -> new Identity<>(set(elementAt(s.size()), just("one"), s))) + .discardL(StateT.modify(s -> new Identity<>(set(elementAt(s.size()), just("two"), s)))) + .>>>runStateT(new ArrayList<>()) + .runIdentity(); + + assertEquals(tuple(UNIT, asList("one", "two")), + result); } @Test From 324763792bf9bc7a21f67e3537544f68ac997663 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 12 Oct 2019 15:55:02 -0500 Subject: [PATCH 266/348] All transformers that can support composable parallelism do --- .../monad/transformer/builtin/EitherT.java | 5 +++- .../monad/transformer/builtin/IdentityT.java | 5 +++- .../monad/transformer/builtin/LazyT.java | 4 +++- .../monad/transformer/builtin/MaybeT.java | 5 +++- .../transformer/builtin/EitherTTest.java | 22 ++++++++++++++++++ .../transformer/builtin/IdentityTTest.java | 21 +++++++++++++++++ .../monad/transformer/builtin/LazyTTest.java | 22 ++++++++++++++++++ .../monad/transformer/builtin/MaybeTTest.java | 22 ++++++++++++++++++ .../transformer/builtin/ReaderTTest.java | 23 ++++++++++++++++++- .../transformer/builtin/WriterTTest.java | 21 +++++++++++++++++ 10 files changed, 145 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java index 340edd066..806fdb636 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -85,7 +85,10 @@ public EitherT fmap(Fn1 fn) { @Override public EitherT zip( Applicative, EitherT> appFn) { - return MonadT.super.zip(appFn).coerce(); + return eitherT(new Compose<>(this., M>>runEitherT()).zip( + new Compose<>(appFn.>>coerce() + .>, M>>runEitherT())) + .getCompose()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java index 42f6f326c..88abc703a 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityT.java @@ -92,7 +92,10 @@ public IdentityT fmap(Fn1 fn) { */ @Override public IdentityT zip(Applicative, IdentityT> appFn) { - return MonadT.super.zip(appFn).coerce(); + return identityT(new Compose<>(this., M>>runIdentityT()).zip( + new Compose<>(appFn.>>coerce() + .>, M>>runIdentityT())) + .getCompose()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java index 5af654230..e9dac4d33 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyT.java @@ -88,7 +88,9 @@ public LazyT fmap(Fn1 fn) { */ @Override public LazyT zip(Applicative, LazyT> appFn) { - return MonadT.super.zip(appFn).coerce(); + return lazyT(new Compose<>(this., M>>runLazyT()).zip( + new Compose<>(appFn.>>coerce() + .>, M>>runLazyT())).getCompose()); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index 3a6cad1f8..ca588a7bc 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -73,7 +73,10 @@ public MaybeT pure(B b) { */ @Override public MaybeT zip(Applicative, MaybeT> appFn) { - return MonadT.super.zip(appFn).coerce(); + return maybeT(new Compose<>(this., M>>runMaybeT()).zip( + new Compose<>(appFn.>>coerce() + .>, M>>runMaybeT())) + .getCompose()); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java index 3fdd45f03..cefc21eda 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java @@ -1,6 +1,9 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -12,13 +15,18 @@ import testsupport.traits.MonadLaws; import testsupport.traits.MonadRecLaws; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; + import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.eitherT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.liftEitherT; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -45,6 +53,20 @@ public void lazyZip() { })).value()); } + @Test(timeout = 500) + public void composedZip() { + CountDownLatch latch = new CountDownLatch(2); + IO countdownAndAwait = io(() -> { + latch.countDown(); + latch.await(); + }); + EitherT, Object, Unit> lifted = liftEitherT().apply(countdownAndAwait); + lifted.discardL(lifted) + .>>runEitherT() + .unsafePerformAsyncIO(Executors.newFixedThreadPool(2)) + .join(); + } + @Test public void staticPure() { EitherT, String, Integer> eitherT = EitherT., String>pureEitherT(pureIdentity()) diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java index 0d31de5d8..07cd9a809 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IdentityTTest.java @@ -1,7 +1,9 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -11,11 +13,16 @@ import testsupport.traits.MonadLaws; import testsupport.traits.MonadRecLaws; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; + 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.Maybe.pureMaybe; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT.identityT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT.liftIdentityT; import static com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT.pureIdentityT; import static org.junit.Assert.assertEquals; @@ -43,4 +50,18 @@ public void staticPure() { IdentityT, Integer> identityT = pureIdentityT(pureMaybe()).apply(1); assertEquals(identityT(just(new Identity<>(1))), identityT); } + + @Test(timeout = 500) + public void composedZip() { + CountDownLatch latch = new CountDownLatch(2); + IO countdownAndAwait = io(() -> { + latch.countDown(); + latch.await(); + }); + IdentityT, Unit> lifted = liftIdentityT().apply(countdownAndAwait); + lifted.discardL(lifted) + .>>runIdentityT() + .unsafePerformAsyncIO(Executors.newFixedThreadPool(2)) + .join(); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java index 8daa73bbe..3db843ed1 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/LazyTTest.java @@ -1,7 +1,10 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -11,11 +14,16 @@ import testsupport.traits.MonadLaws; import testsupport.traits.MonadRecLaws; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; + import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monad.transformer.builtin.LazyT.lazyT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.LazyT.liftLazyT; import static com.jnape.palatable.lambda.monad.transformer.builtin.LazyT.pureLazyT; import static org.junit.Assert.assertEquals; @@ -43,4 +51,18 @@ public void staticPure() { LazyT, Integer> lazyT = pureLazyT(pureIdentity()).apply(1); assertEquals(lazyT(new Identity<>(lazy(1))), lazyT); } + + @Test(timeout = 500) + public void composedZip() { + CountDownLatch latch = new CountDownLatch(2); + IO countdownAndAwait = io(() -> { + latch.countDown(); + latch.await(); + }); + LazyT, Unit> lifted = liftLazyT().apply(countdownAndAwait); + lifted.discardL(lifted) + .>>runLazyT() + .unsafePerformAsyncIO(Executors.newFixedThreadPool(2)) + .join(); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java index cba72968a..6af53f359 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java @@ -1,7 +1,10 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; @@ -12,12 +15,17 @@ import testsupport.traits.MonadLaws; import testsupport.traits.MonadRecLaws; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; + import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.liftMaybeT; import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.maybeT; import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.pureMaybeT; import static com.jnape.palatable.traitor.framework.Subjects.subjects; @@ -48,4 +56,18 @@ public void staticPure() { MaybeT, Integer> maybeT = pureMaybeT(pureIdentity()).apply(1); assertEquals(maybeT(new Identity<>(just(1))), maybeT); } + + @Test(timeout = 500) + public void composedZip() { + CountDownLatch latch = new CountDownLatch(2); + IO countdownAndAwait = io(() -> { + latch.countDown(); + latch.await(); + }); + MaybeT, Unit> lifted = liftMaybeT().apply(countdownAndAwait); + lifted.discardL(lifted) + .>>runMaybeT() + .unsafePerformAsyncIO(Executors.newFixedThreadPool(2)) + .join(); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java index 55ee2eec7..3ea0710ff 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java @@ -1,7 +1,9 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -10,11 +12,16 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; -import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadReaderLaws; +import testsupport.traits.MonadRecLaws; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monad.transformer.builtin.ReaderT.readerT; import static org.junit.Assert.assertEquals; import static testsupport.traits.Equivalence.equivalence; @@ -57,4 +64,18 @@ public void staticPure() { ReaderT.>pureReaderT(pureIdentity()).apply(1); assertEquals(new Identity<>(1), readerT.runReaderT("foo")); } + + @Test(timeout = 500) + public void composedZip() { + CountDownLatch latch = new CountDownLatch(2); + IO countdownAndAwait = io(() -> { + latch.countDown(); + latch.await(); + }); + ReaderT, Unit> lifted = ReaderT.liftReaderT().apply(countdownAndAwait); + lifted.discardL(lifted) + .>runReaderT(UNIT) + .unsafePerformAsyncIO(Executors.newFixedThreadPool(2)) + .join(); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java index e0017a20a..932fe7011 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java @@ -1,7 +1,9 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -13,11 +15,16 @@ import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadWriterLaws; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; + import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; +import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monad.transformer.builtin.WriterT.writerT; import static com.jnape.palatable.lambda.monoid.builtin.Join.join; +import static com.jnape.palatable.lambda.monoid.builtin.Trivial.trivial; import static org.junit.Assert.assertEquals; import static testsupport.traits.Equivalence.equivalence; @@ -64,4 +71,18 @@ public void staticLift() { assertEquals(new Identity<>(tuple(1, "")), apply.runWriterT(join())); } + + @Test(timeout = 500) + public void composedZip() { + CountDownLatch latch = new CountDownLatch(2); + IO countdownAndAwait = io(() -> { + latch.countDown(); + latch.await(); + }); + WriterT, Unit> lifted = WriterT.liftWriterT().apply(countdownAndAwait); + lifted.discardL(lifted) + .>>runWriterT(trivial()) + .unsafePerformAsyncIO(Executors.newFixedThreadPool(2)) + .join(); + } } \ No newline at end of file From d154585921f7b0fd2e7f71d61f2d719d6a7800d5 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Oct 2019 15:29:20 -0500 Subject: [PATCH 267/348] Eliminating unnecessary additional fmap per element via traverse --- .../palatable/lambda/traversable/LambdaIterable.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) 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 9859dac85..0134549b1 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -135,11 +135,10 @@ public LambdaIterable trampolineM( AppTrav extends Applicative> AppTrav traverse(Fn1> fn, Fn1 pure) { return FoldRight.foldRight( - (a, lglb) -> fn.apply(a) - .lazyZip(lglb., App>>fmap(appTrav -> appTrav - .fmap(travB -> b -> (TravB) wrap(cons(b, ((LambdaIterable) travB).unwrap()))))) - .fmap(appTrav -> (AppTrav) appTrav), - lazy(pure.apply((TravB) empty())), + (a, lazyAppTrav) -> (Lazy) fn.apply(a) + .lazyZip(lazyAppTrav., App>>fmap(appTrav -> appTrav + .fmap(travB -> b -> (TravB) wrap(cons(b, ((LambdaIterable) travB).unwrap()))))), + lazy(() -> pure.apply((TravB) empty())), as ).value(); } From d65283049ef7f29089668442fb5885c3e7ae518d Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Oct 2019 16:07:06 -0500 Subject: [PATCH 268/348] Updating CHANGELOG --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b68b98fdd..d1e944819 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] +### Changed +- All monad transformers that can support composable parallelism do support it + ### Added - `Writer`, the writer monad - `EndoK`, a monoid formed under endomorphism for any monad +- `AutoBracket`, a specialized form of `Bracket` for `AutoCloseable` that closes the resource during cleanup + +### Fixed +- `SafeT#zip` is now stack-safe regardless of the underlying monad's `zip` implementation ## [5.0.0] - 2019-09-23 ### Changed From a8c403de5629077a7736ab10ee81d05239c883e7 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Oct 2019 16:35:48 -0500 Subject: [PATCH 269/348] Deprecating Force --- CHANGELOG.md | 4 ++- .../lambda/functions/builtin/fn1/Force.java | 4 +++ .../functions/builtin/fn1/ForceTest.java | 29 ------------------- .../functions/builtin/fn2/DropWhileTest.java | 5 ++-- .../functions/builtin/fn2/FilterTest.java | 5 ++-- .../functions/builtin/fn2/TakeWhileTest.java | 5 ++-- 6 files changed, 13 insertions(+), 39 deletions(-) delete mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ForceTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d1e944819..a9a96405d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Fixed - `SafeT#zip` is now stack-safe regardless of the underlying monad's `zip` implementation +### Deprecated +- `Force`, in favor if traversing into an `IO` and explicitly running it + ## [5.0.0] - 2019-09-23 ### Changed - ***Breaking Change***: `MonadT` is now witnessed by a parameter for better subtyping, and no longer requires a common @@ -52,7 +55,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Deprecated - `Peek`, `Peek2`, `Maybe#peek`, and `Either#peek` in favor of explicitly matching into `IO` and running it -- `Force`, in favor if traversing into an `IO` and explicitly running it - `IO#exceptionally` in favor of `IO#catchError` (from `MonadError`) ## [4.0.0] - 2019-05-20 diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java index a198fc9ff..1c12a04fa 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Force.java @@ -1,13 +1,17 @@ package com.jnape.palatable.lambda.functions.builtin.fn1; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.traversable.LambdaIterable; /** * Force a full iteration of an {@link Iterable}, presumably to perform any side-effects contained therein. Returns the * {@link Iterable} back. * * @param the Iterable element type + * @deprecated in favor of {@link LambdaIterable#traverse(Fn1, Fn1) traversing} into an {@link IO} and running it */ +@Deprecated public final class Force implements Fn1, Iterable> { private static final Force INSTANCE = new Force<>(); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ForceTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ForceTest.java deleted file mode 100644 index 394d85ddd..000000000 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/ForceTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.jnape.palatable.lambda.functions.builtin.fn1; - -import org.junit.Test; - -import java.util.concurrent.atomic.AtomicInteger; - -import static com.jnape.palatable.lambda.functions.builtin.fn1.Force.force; -import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; -import static java.util.Arrays.asList; -import static org.junit.Assert.assertEquals; - -public class ForceTest { - - @Test - public void performsAnySideEffects() { - AtomicInteger counter = new AtomicInteger(); - Iterable ints = map(x -> { - counter.incrementAndGet(); - return x; - }, asList(1, 2, 3)); - - assertEquals(0, counter.get()); - - force(ints); - force(ints); - - assertEquals(6, counter.get()); - } -} \ No newline at end of file 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 e168d749a..83903f451 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 @@ -15,7 +15,6 @@ 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; @@ -50,13 +49,13 @@ public void dropsNoElementsIfPredicateImmediatelyFails() { public void deforestingExecutesPredicatesInOrder() { List innerInvocations = new ArrayList<>(); List outerInvocations = new ArrayList<>(); - force(dropWhile(y -> { + dropWhile(y -> { outerInvocations.add(y); return true; }, dropWhile(x -> { innerInvocations.add(x); return x > 2; - }, asList(1, 2, 3)))); + }, asList(1, 2, 3))).forEach(__ -> {}); 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 73ca133bc..cc589a984 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 @@ -15,7 +15,6 @@ 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; @@ -42,13 +41,13 @@ public void filtersOutMatchingElements() { public void deforestingExecutesPredicatesInOrder() { List innerInvocations = new ArrayList<>(); List outerInvocations = new ArrayList<>(); - force(filter(y -> { + filter(y -> { outerInvocations.add(y); return true; }, filter(x -> { innerInvocations.add(x); return x % 2 == 0; - }, asList(1, 2, 3)))); + }, asList(1, 2, 3))).forEach(__ -> {}); assertThat(innerInvocations, iterates(1, 2, 3)); assertThat(outerInvocations, iterates(2)); } 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 30a4172b3..5e34c3403 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 @@ -15,7 +15,6 @@ 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; @@ -55,13 +54,13 @@ public void takesNoElementsIfPredicateImmediatelyFails() { public void deforestingExecutesPredicatesInOrder() { List innerInvocations = new ArrayList<>(); List outerInvocations = new ArrayList<>(); - force(takeWhile(y -> { + takeWhile(y -> { outerInvocations.add(y); return true; }, takeWhile(x -> { innerInvocations.add(x); return x < 3; - }, asList(1, 2, 3)))); + }, asList(1, 2, 3))).forEach(__ -> {}); assertThat(innerInvocations, iterates(1, 2, 3)); assertThat(outerInvocations, iterates(1, 2)); } From 5ffcd6c60ee82f98716c87f984bb939a639fd0e8 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Oct 2019 16:50:20 -0500 Subject: [PATCH 270/348] [maven-release-plugin] prepare release lambda-5.1.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aca3bad76..0a12b1146 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.0.1-SNAPSHOT + 5.1.0 jar Lambda From 39d54649d1dd7df1b707d412817713c1a080e5cd Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Oct 2019 16:50:27 -0500 Subject: [PATCH 271/348] [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 0a12b1146..c94448fa2 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.1.0 + 5.1.1-SNAPSHOT jar Lambda From bef44da9c6a6656b200bc82bdb8af9798fef6bba Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 22 Oct 2019 18:52:04 -0500 Subject: [PATCH 272/348] Updating CHANGELOG and README --- CHANGELOG.md | 7 ++++++- README.md | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9a96405d..3a6900a75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] + +There are currently no unreleased changes + +## [5.1.0] - 2019-10-13 ### Changed - All monad transformers that can support composable parallelism do support it @@ -539,7 +543,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-5.0.0...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-5.1.0...HEAD +[5.1.0]: https://github.com/palatable/lambda/compare/lambda-5.0.0...lambda-5.1.0 [5.0.0]: https://github.com/palatable/lambda/compare/lambda-4.0.0...lambda-5.0.0 [4.0.0]: https://github.com/palatable/lambda/compare/lambda-3.3.0...lambda-4.0.0 [3.3.0]: https://github.com/palatable/lambda/compare/lambda-3.2.0...lambda-3.3.0 diff --git a/README.md b/README.md index be008c911..005924e67 100644 --- a/README.md +++ b/README.md @@ -60,14 +60,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 5.0.0 + 5.1.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '5.0.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '5.1.0' ``` Examples From 233b4f0e68155cb1988a32ec2e6669a0e8d76dd9 Mon Sep 17 00:00:00 2001 From: John Napier Date: Wed, 30 Oct 2019 09:28:04 -0500 Subject: [PATCH 273/348] Adding Community section --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 005924e67..fdd0981c0 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Functional patterns for Java - [Either](#either) - [Lenses](#lenses) - [Notes](#notes) + - [Community](#community) - [License](#license) Background @@ -739,6 +740,13 @@ Wherever possible, _lambda_ maintains interface compatibility with similar, fami Unfortunately, due to Java's type hierarchy and inheritance inconsistencies, this is not always possible. One surprising example of this is how `Fn1` extends `j.u.f.Function`, but `Fn2` does not extend `j.u.f.BiFunction`. This is because `j.u.f.BiFunction` itself does not extend `j.u.f.Function`, but it does define methods that collide with `j.u.f.Function`. For this reason, both `Fn1` and `Fn2` cannot extend their Java counterparts without sacrificing their own inheritance hierarchy. These types of asymmetries are, unfortunately, not uncommon; however, wherever these situations arise, measures are taken to attempt to ease the transition in and out of core Java types (in the case of `Fn2`, a supplemental `#toBiFunction` method is added). I do not take these inconveniences for granted, and I'm regularly looking for ways to minimize the negative impact of this as much as possible. Suggestions and use cases that highlight particular pain points here are particularly appreciated. +Community +----- +There are some open-sourced community projects that also leverage or extend _lambda_: these projects are listed below. If you use _lambda_ in your own open-sourced project, feel free to create an issue and I'll be happy to review the project and add it to this section! + +- [Enhanced Iterables](https://github.com/kschuetz/enhanced-iterables) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) +- [Collection Views](https://github.com/kschuetz/collection-views) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) + License ------- From ec22f1a65cf5cbf9f825251824d1c6910ef3b8c2 Mon Sep 17 00:00:00 2001 From: John Napier Date: Wed, 30 Oct 2019 09:32:46 -0500 Subject: [PATCH 274/348] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fdd0981c0..edaf4dde9 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ Functional patterns for Java - [CoProducts](#coproducts) - [Either](#either) - [Lenses](#lenses) - - [Notes](#notes) - - [Community](#community) + - [Notes](#notes) + - [Community](#community) - [License](#license) Background @@ -742,7 +742,7 @@ Unfortunately, due to Java's type hierarchy and inheritance inconsistencies, thi Community ----- -There are some open-sourced community projects that also leverage or extend _lambda_: these projects are listed below. If you use _lambda_ in your own open-sourced project, feel free to create an issue and I'll be happy to review the project and add it to this section! +There are some open-sourced community projects that depend on _lambda_ for their own functionality: these projects are listed below (note that these projects are _not_ affiliated with lambda, and have their own maintainers). If you use _lambda_ in your own open-sourced project, feel free to create an issue and I'll be happy to review the project and add it to this section! - [Enhanced Iterables](https://github.com/kschuetz/enhanced-iterables) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) - [Collection Views](https://github.com/kschuetz/collection-views) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) From 974fa525019b886968845d11f6e367e50d565fd0 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 20 Nov 2019 09:57:15 -0600 Subject: [PATCH 275/348] HList#cons static factory method auto-promotes --- .../palatable/lambda/adt/hlist/HList.java | 6 +++-- .../palatable/lambda/adt/hlist/HListTest.java | 24 ++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) 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 91f19edbe..421855a10 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 @@ -1,5 +1,7 @@ package com.jnape.palatable.lambda.adt.hlist; +import com.jnape.palatable.lambda.functions.builtin.fn1.Downcast; + import java.util.Objects; /** @@ -63,7 +65,7 @@ public static HNil nil() { * @return the newly created HList */ public static HCons cons(Head head, Tail tail) { - return new HCons<>(head, tail); + return Downcast., HCons>downcast(tail.cons(head)); } /** @@ -271,7 +273,7 @@ public final boolean equals(Object other) { if (other instanceof HCons) { HCons that = (HCons) other; return this.head.equals(that.head) - && this.tail.equals(that.tail); + && this.tail.equals(that.tail); } return false; } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java index 6be65b6dc..1f75ce450 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java @@ -2,15 +2,9 @@ import org.junit.Test; -import static com.jnape.palatable.lambda.adt.hlist.HList.cons; -import static com.jnape.palatable.lambda.adt.hlist.HList.nil; -import static com.jnape.palatable.lambda.adt.hlist.HList.singletonHList; -import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import static com.jnape.palatable.lambda.adt.hlist.HList.*; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.*; public class HListTest { @@ -36,6 +30,18 @@ public void convenienceStaticFactoryMethods() { assertEquals(nil().cons(false).cons(4.0).cons("3").cons('2').cons(1), tuple(1, '2', "3", 4.0, false)); } + @Test + public void autoPromotion() { + assertThat(cons(1, nil()), instanceOf(SingletonHList.class)); + assertThat(cons(1, singletonHList(1)), instanceOf(Tuple2.class)); + assertThat(cons(1, tuple(1, 1)), instanceOf(Tuple3.class)); + assertThat(cons(1, tuple(1, 1, 1)), instanceOf(Tuple4.class)); + assertThat(cons(1, tuple(1, 1, 1, 1)), instanceOf(Tuple5.class)); + assertThat(cons(1, tuple(1, 1, 1, 1, 1)), instanceOf(Tuple6.class)); + assertThat(cons(1, tuple(1, 1, 1, 1, 1, 1)), instanceOf(Tuple7.class)); + assertThat(cons(1, tuple(1, 1, 1, 1, 1, 1, 1)), instanceOf(Tuple8.class)); + } + @Test public void nilReusesInstance() { assertSame(nil(), nil()); From 74a58a0f5b929eba9b6145121121ddaf35d1ea46 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 20 Nov 2019 09:58:22 -0600 Subject: [PATCH 276/348] Updating CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a6900a75..0d82489f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] -There are currently no unreleased changes +### Changed +- `HList#cons` static factory method auto-promotes to specialized `HList` if there is one ## [5.1.0] - 2019-10-13 ### Changed From 99acf00c88c2353384189de0ab3044fd93c18fdf Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 10 Dec 2019 14:19:11 -0600 Subject: [PATCH 277/348] Adding MergeHMaps, a Monoid merging HMaps by using key-specific semigroups --- CHANGELOG.md | 3 + .../lambda/monoid/builtin/MergeHMaps.java | 81 +++++++++++++++++++ .../lambda/monoid/builtin/MergeHMapsTest.java | 62 ++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeHMaps.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeHMapsTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d82489f9..488f8b414 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - `HList#cons` static factory method auto-promotes to specialized `HList` if there is one +### Added +- `MergeHMaps`, a `Monoid` that merges `HMap`s by merging the values via key-specified `Semigroup`s + ## [5.1.0] - 2019-10-13 ### Changed - All monad transformers that can support composable parallelism do support it diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeHMaps.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeHMaps.java new file mode 100644 index 000000000..fc2f28c95 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/MergeHMaps.java @@ -0,0 +1,81 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.hmap.HMap; +import com.jnape.palatable.lambda.adt.hmap.TypeSafeKey; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft; +import com.jnape.palatable.lambda.monoid.Monoid; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import java.util.Map; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.maybe; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map; +import static com.jnape.palatable.lambda.monoid.builtin.Last.last; +import static com.jnape.palatable.lambda.monoid.builtin.Present.present; +import static com.jnape.palatable.lambda.optics.functions.Set.set; +import static com.jnape.palatable.lambda.optics.lenses.MapLens.valueAt; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyMap; + +/** + * A {@link Monoid} instance formed by merging {@link HMap HMaps} using the chosen + * {@link TypeSafeKey} -> {@link Semigroup} + * {@link MergeHMaps#key(TypeSafeKey, Semigroup) mappings}, defaulting to {@link Last} in case no + * {@link Semigroup} has been chosen for a given {@link TypeSafeKey}. + */ +public final class MergeHMaps implements Monoid { + + private final Map, Fn2> bindings; + private final Φ> defaultBinding; + + private MergeHMaps(Map, Fn2> bindings, + Φ> defaultBinding) { + this.bindings = bindings; + this.defaultBinding = defaultBinding; + } + + public MergeHMaps key(TypeSafeKey key, Semigroup semigroup) { + return new MergeHMaps(set(valueAt(key), just(merge(key, present(semigroup))), bindings), defaultBinding); + } + + @Override + public HMap identity() { + return HMap.emptyHMap(); + } + + @Override + public HMap checkedApply(HMap x, HMap y) throws Throwable { + return reduceLeft(asList(x, y)); + } + + @Override + public HMap foldMap(Fn1 fn, Iterable bs) { + return FoldLeft.foldLeft((acc, m) -> FoldLeft.foldLeft((result, k) -> maybe(bindings.get(k)) + .orElseGet(() -> defaultBinding.eliminate(k)) + .apply(result, m), acc, m.keys()), identity(), map(fn, bs)); + } + + public static MergeHMaps mergeHMaps() { + return new MergeHMaps(emptyMap(), new Φ>() { + @Override + public Fn2 eliminate(TypeSafeKey key) { + return merge(key, last()); + } + }); + } + + private static Fn2 merge(TypeSafeKey key, Semigroup> semigroup) { + return (x, y) -> semigroup.apply(x.get(key), y.get(key)) + .fmap(a -> x.put(key, a)) + .orElse(x); + } + + @SuppressWarnings({"NonAsciiCharacters"}) + private interface Φ { + R eliminate(TypeSafeKey key); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeHMapsTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeHMapsTest.java new file mode 100644 index 000000000..0bf2d978b --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/MergeHMapsTest.java @@ -0,0 +1,62 @@ +package com.jnape.palatable.lambda.monoid.builtin; + +import com.jnape.palatable.lambda.adt.hmap.TypeSafeKey; +import org.junit.Test; + +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.HMap.singletonHMap; +import static com.jnape.palatable.lambda.adt.hmap.TypeSafeKey.typeSafeKey; +import static com.jnape.palatable.lambda.monoid.builtin.Join.join; +import static com.jnape.palatable.lambda.monoid.builtin.MergeHMaps.mergeHMaps; +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +public class MergeHMapsTest { + + @Test + public void allKeysAccountedFor() { + TypeSafeKey.Simple stringKey = typeSafeKey(); + MergeHMaps mergeHMaps = mergeHMaps().key(stringKey, join()); + + assertEquals(emptyHMap(), mergeHMaps.apply(emptyHMap(), emptyHMap())); + assertEquals(singletonHMap(stringKey, "foo"), + mergeHMaps.apply(singletonHMap(stringKey, "foo"), emptyHMap())); + assertEquals(singletonHMap(stringKey, "foobar"), + mergeHMaps.apply(singletonHMap(stringKey, "foo"), + singletonHMap(stringKey, "bar"))); + } + + @Test + public void unaccountedForKeyUsesLastByDefault() { + TypeSafeKey.Simple stringKey = typeSafeKey(); + + assertEquals(singletonHMap(stringKey, "foo"), + mergeHMaps().apply(singletonHMap(stringKey, "foo"), emptyHMap())); + assertEquals(singletonHMap(stringKey, "bar"), + mergeHMaps().apply(emptyHMap(), singletonHMap(stringKey, "bar"))); + assertEquals(singletonHMap(stringKey, "bar"), + mergeHMaps().apply(singletonHMap(stringKey, "foo"), singletonHMap(stringKey, "bar"))); + } + + @Test + public void sparseKeysAcrossMaps() { + TypeSafeKey.Simple stringKey = typeSafeKey(); + TypeSafeKey.Simple intKey = typeSafeKey(); + TypeSafeKey.Simple boolKey = typeSafeKey(); + + MergeHMaps mergeHMaps = mergeHMaps() + .key(stringKey, join()) + .key(intKey, Integer::sum); + + assertEquals(hMap(stringKey, "foobar", + intKey, 3, + boolKey, false), + mergeHMaps.reduceLeft(asList(singletonHMap(stringKey, "foo"), + singletonHMap(intKey, 1), + singletonHMap(boolKey, true), + hMap(stringKey, "bar", + intKey, 2, + boolKey, false)))); + } +} \ No newline at end of file From 93be6ed6a76eddd8df48d3f3e6d7bca94954ef52 Mon Sep 17 00:00:00 2001 From: John Napier Date: Wed, 1 Jan 2020 18:16:08 -0600 Subject: [PATCH 278/348] Shameless self-promotion button --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..66b54c05c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: [jnape] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] From e31ad461775a650b864058b524214684fb23ddea Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 26 Jan 2020 15:30:05 -0600 Subject: [PATCH 279/348] Javadoc --- src/main/java/com/jnape/palatable/lambda/functions/Fn1.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index 3f2be1e92..f21e70e23 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -123,7 +123,7 @@ default Fn1 flatMap(Fn1>> f) { } /** - * Also left-to-right composition (sadly). + * Left-to-right composition. * * @param the return type of the next function to invoke * @param f the function to invoke with this function's return value From c87ac5b2e66c0edd81a23258c8f7f880c6a6e6a6 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 8 Feb 2020 16:14:50 -0600 Subject: [PATCH 280/348] Mockito is a test dependency; missed this in a previous release --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index c94448fa2..5f84c2dd2 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,7 @@ org.mockito mockito-core 2.28.2 + test com.jnape.palatable From ffb4c2721ea3b81612b01b64c315bed7acd5d6dc Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Thu, 24 Oct 2019 11:57:03 -0500 Subject: [PATCH 281/348] Add utility functions for interoperability with java.util.Comparator - Add ComparisonRelation to encapsulate Comparator/Comparable#compare semantics - Add Compare to abstract over Comparator#compare using ComparisonRelation - Add comparator compatible functions (CmpEqWith, GTEWith, GTWith, LTEWith, LTWith) --- .../lambda/functions/builtin/fn3/CmpEqBy.java | 5 +- .../functions/builtin/fn3/CmpEqWith.java | 62 +++++++++++++ .../lambda/functions/builtin/fn3/Compare.java | 56 ++++++++++++ .../lambda/functions/builtin/fn3/GTBy.java | 5 +- .../lambda/functions/builtin/fn3/GTEBy.java | 6 +- .../lambda/functions/builtin/fn3/GTEWith.java | 62 +++++++++++++ .../lambda/functions/builtin/fn3/GTWith.java | 62 +++++++++++++ .../lambda/functions/builtin/fn3/LTBy.java | 4 +- .../lambda/functions/builtin/fn3/LTEBy.java | 5 +- .../lambda/functions/builtin/fn3/LTEWith.java | 62 +++++++++++++ .../lambda/functions/builtin/fn3/LTWith.java | 62 +++++++++++++ .../ordering/ComparisonRelation.java | 89 +++++++++++++++++++ .../lambda/semigroup/builtin/MaxBy.java | 1 + .../lambda/semigroup/builtin/MaxWith.java | 52 +++++++++++ .../lambda/semigroup/builtin/MinWith.java | 52 +++++++++++ .../functions/builtin/fn3/CmpEqWithTest.java | 19 ++++ .../functions/builtin/fn3/CompareTest.java | 19 ++++ .../functions/builtin/fn3/GTEWithTest.java | 21 +++++ .../functions/builtin/fn3/GTWithTest.java | 20 +++++ .../functions/builtin/fn3/LTEWithTest.java | 21 +++++ .../functions/builtin/fn3/LTWithTest.java | 20 +++++ .../ordering/ComparisonRelationTest.java | 23 +++++ .../lambda/semigroup/builtin/MaxWithTest.java | 21 +++++ .../lambda/semigroup/builtin/MinWithTest.java | 21 +++++ 24 files changed, 763 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWith.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Compare.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWith.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTWith.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWith.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTWith.java create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelation.java create mode 100644 src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxWith.java create mode 100644 src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinWith.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWithTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CompareTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWithTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTWithTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWithTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTWithTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelationTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxWithTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinWithTest.java diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java index 3b483aeaf..a6e04baa9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqBy.java @@ -6,7 +6,9 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; +import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqWith.cmpEqWith; import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; +import static java.util.Comparator.comparing; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values @@ -16,6 +18,7 @@ * @param the value type * @param the mapped comparison type * @see CmpEq + * @see CmpEqWith * @see LTBy * @see GTBy */ @@ -28,7 +31,7 @@ private CmpEqBy() { @Override public Boolean checkedApply(Fn1 compareFn, A x, A y) { - return compareFn.apply(x).compareTo(compareFn.apply(y)) == 0; + return cmpEqWith(comparing(compareFn.toFunction()), x, y); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWith.java new file mode 100644 index 000000000..0a0c1f1ce --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWith.java @@ -0,0 +1,62 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.Comparator; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Compare.compare; +import static com.jnape.palatable.lambda.functions.ordering.ComparisonRelation.equal; +import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; + +/** + * Given a {@link Comparator} from some type A and two values of type A, return true + * if the first value is strictly equal to the second value (according to {@link Comparator#compare(A, A)} + * otherwise, return false. + * + * @param the value type + * @see CmpEqBy + * @see LTBy + * @see GTBy + * @see Compare + */ +public final class CmpEqWith implements Fn3, A, A, Boolean> { + + private static final CmpEqWith INSTANCE = new CmpEqWith<>(); + + private CmpEqWith() { + } + + @Override + public BiPredicate apply(Comparator compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Comparator compareFn, A x) { + return predicate(Fn3.super.apply(compareFn, x)); + } + + @SuppressWarnings("unchecked") + public static CmpEqWith cmpEqWith() { + return (CmpEqWith) INSTANCE; + } + + public static BiPredicate cmpEqWith(Comparator comparator) { + return CmpEqWith.cmpEqWith().apply(comparator); + } + + public static Predicate cmpEqWith(Comparator comparator, A x) { + return CmpEqWith.cmpEqWith(comparator).apply(x); + } + + public static Boolean cmpEqWith(Comparator comparator, A x, A y) { + return cmpEqWith(comparator, x).apply(y); + } + + @Override + public Boolean checkedApply(Comparator comparator, A a, A a2) { + return compare(comparator, a, a2).equals(equal()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Compare.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Compare.java new file mode 100644 index 000000000..4f0bea533 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Compare.java @@ -0,0 +1,56 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.ordering.ComparisonRelation; + +import java.util.Comparator; + +/** + * Given a {@link Comparator} from some type A and two values of type A, return a + * {@link ComparisonRelation} of the first value with reference to the second value (according to {@link Comparator#compare(A, A)}. + * The order of parameters is flipped with respect to {@link Comparator#compare(A, A)} for more idiomatic partial application. + * + *

+ * Example: + *

+ * {@code
+ *  Compare.compare(naturalOrder(), 1, 2); // ComparisonRelation.GreaterThan
+ *  Compare.compare(naturalOrder(), 2, 1); // ComparisonRelation.LessThan
+ *  Compare.compare(naturalOrder(), 1, 1); // ComparisonRelation.Equal
+ * }
+ * 
+ *

+ * + * @param
the value type + * @see Comparator + * @see Compare + */ +public final class Compare implements Fn3, A, A, ComparisonRelation> { + private static final Compare INSTANCE = new Compare<>(); + + private Compare() { } + + @Override + public ComparisonRelation checkedApply(Comparator aComparator, A a, A a2) throws Throwable { + return ComparisonRelation.fromInt(aComparator.compare(a2, a)); + } + + @SuppressWarnings("unchecked") + public static Compare compare() { + return (Compare) INSTANCE; + } + + public static Fn2 compare(Comparator comparator) { + return Compare.compare().apply(comparator); + } + + public static Fn1 compare(Comparator comparator, A a) { + return compare(comparator).apply(a); + } + + public static ComparisonRelation compare(Comparator aComparator, A a, A a2) { + return compare(aComparator, a).apply(a2); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java index cb9b45168..caddec12e 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTBy.java @@ -6,7 +6,9 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTWith.gtWith; import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; +import static java.util.Comparator.comparing; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values @@ -16,6 +18,7 @@ * @param the value type * @param the mapped comparison type * @see GT + * @see GTWith * @see LTBy */ public final class GTBy> implements Fn3, A, A, Boolean> { @@ -27,7 +30,7 @@ private GTBy() { @Override public Boolean checkedApply(Fn1 compareFn, A y, A x) { - return compareFn.apply(x).compareTo(compareFn.apply(y)) > 0; + return gtWith(comparing(compareFn.toFunction()), y, x); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java index 30ef09852..7a1b4acad 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEBy.java @@ -6,8 +6,9 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy; +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTEWith.gteWith; import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; +import static java.util.Comparator.comparing; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values @@ -18,6 +19,7 @@ * @param the value type * @param the mapped comparison type * @see GTE + * @see GTEWith * @see LTEBy */ public final class GTEBy> implements Fn3, A, A, Boolean> { @@ -29,7 +31,7 @@ private GTEBy() { @Override public Boolean checkedApply(Fn1 compareFn, A y, A x) { - return GTBy.gtBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x); + return gteWith(comparing(compareFn.toFunction()), y, x); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWith.java new file mode 100644 index 000000000..7a3c8cc6d --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWith.java @@ -0,0 +1,62 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.builtin.fn2.GTE; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.Comparator; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTWith.ltWith; +import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; + +/** + * Given a {@link Comparator} from some type A and two values of type A, + * return true if the second value is greater than or equal to the first value in + * terms of their mapped B results according to {@link Comparator#compare(A, A)}; + * otherwise, return false. + * + * @param the value type + * @see GTE + * @see GTEBy + * @see LTEWith + */ +public final class GTEWith implements Fn3, A, A, Boolean> { + + private static final GTEWith INSTANCE = new GTEWith<>(); + + private GTEWith() { + } + + @Override + public BiPredicate apply(Comparator compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Comparator compareFn, A x) { + return predicate(Fn3.super.apply(compareFn, x)); + } + + @SuppressWarnings("unchecked") + public static GTEWith gteWith() { + return (GTEWith) INSTANCE; + } + + public static BiPredicate gteWith(Comparator comparator) { + return GTEWith.gteWith().apply(comparator); + } + + public static Predicate gteWith(Comparator comparator, A y) { + return GTEWith.gteWith(comparator).apply(y); + } + + public static Boolean gteWith(Comparator comparator, A y, A x) { + return gteWith(comparator, y).apply(x); + } + + @Override + public Boolean checkedApply(Comparator comparator, A a, A a2) { + return !ltWith(comparator, a, a2); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTWith.java new file mode 100644 index 000000000..d65bec00f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTWith.java @@ -0,0 +1,62 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.builtin.fn2.GT; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.Comparator; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Compare.compare; +import static com.jnape.palatable.lambda.functions.ordering.ComparisonRelation.greaterThan; +import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; + +/** + * Given a {@link Comparator} from some type A and two values of type A, + * return true if the second value is strictly greater than the first value in + * terms of their mapped B results; otherwise, return false. + * + * @param the value type + * @see GT + * @see GTBy + * @see LTWith + */ +public final class GTWith implements Fn3, A, A, Boolean> { + + private static final GTWith INSTANCE = new GTWith<>(); + + private GTWith() { + } + + @Override + public BiPredicate apply(Comparator compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Comparator compareFn, A x) { + return predicate(Fn3.super.apply(compareFn, x)); + } + + @SuppressWarnings("unchecked") + public static GTWith gtWith() { + return (GTWith) INSTANCE; + } + + public static BiPredicate gtWith(Comparator comparator) { + return GTWith.gtWith().apply(comparator); + } + + public static Predicate gtWith(Comparator comparator, A y) { + return GTWith.gtWith(comparator).apply(y); + } + + public static Boolean gtWith(Comparator comparator, A y, A x) { + return gtWith(comparator, y).apply(x); + } + + @Override + public Boolean checkedApply(Comparator comparator, A a, A a2) { + return compare(comparator, a, a2).equals(greaterThan()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java index c442d9871..05e163844 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTBy.java @@ -6,7 +6,9 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTWith.ltWith; import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; +import static java.util.Comparator.comparing; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values @@ -27,7 +29,7 @@ private LTBy() { @Override public Boolean checkedApply(Fn1 compareFn, A y, A x) { - return compareFn.apply(x).compareTo(compareFn.apply(y)) < 0; + return ltWith(comparing(compareFn.toFunction()), y, x); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java index bc755470d..4c377d583 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEBy.java @@ -6,7 +6,8 @@ import com.jnape.palatable.lambda.functions.specialized.BiPredicate; import com.jnape.palatable.lambda.functions.specialized.Predicate; -import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy; +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTEWith.lteWith; +import static java.util.Comparator.comparing; /** * Given a mapping function from some type A to some {@link Comparable} type B and two values @@ -28,7 +29,7 @@ private LTEBy() { @Override public Boolean checkedApply(Fn1 compareFn, A y, A x) { - return LTBy.ltBy(compareFn).or(cmpEqBy(compareFn)).apply(y, x); + return lteWith(comparing(compareFn.toFunction()), y, x); } @Override diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWith.java new file mode 100644 index 000000000..06e621d3f --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWith.java @@ -0,0 +1,62 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.builtin.fn2.LTE; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.Comparator; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTWith.gtWith; +import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; + +/** + * Given a {@link Comparator} from some type A and two values of type A, + * return true if the second value is less than or equal to the first value in + * terms of their mapped B results according to {@link Comparator#compare(A, A)}; + * otherwise, return false. + * + * @param the value type + * @see LTE + * @see LTEBy + * @see GTEWith + */ +public final class LTEWith implements Fn3, A, A, Boolean> { + + private static final LTEWith INSTANCE = new LTEWith<>(); + + private LTEWith() { + } + + @Override + public BiPredicate apply(Comparator compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Comparator compareFn, A x) { + return predicate(Fn3.super.apply(compareFn, x)); + } + + @SuppressWarnings("unchecked") + public static LTEWith lteWith() { + return (LTEWith) INSTANCE; + } + + public static BiPredicate lteWith(Comparator comparator) { + return LTEWith.lteWith().apply(comparator); + } + + public static Predicate lteWith(Comparator comparator, A y) { + return LTEWith.lteWith(comparator).apply(y); + } + + public static Boolean lteWith(Comparator comparator, A y, A x) { + return lteWith(comparator, y).apply(x); + } + + @Override + public Boolean checkedApply(Comparator comparator, A a, A a2) { + return !gtWith(comparator, a, a2); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTWith.java new file mode 100644 index 000000000..14652a4c6 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTWith.java @@ -0,0 +1,62 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import com.jnape.palatable.lambda.functions.Fn3; +import com.jnape.palatable.lambda.functions.builtin.fn2.LT; +import com.jnape.palatable.lambda.functions.specialized.BiPredicate; +import com.jnape.palatable.lambda.functions.specialized.Predicate; + +import java.util.Comparator; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Compare.compare; +import static com.jnape.palatable.lambda.functions.ordering.ComparisonRelation.lessThan; +import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; + +/** + * Given a comparator for some type A and two values of type A, + * return true if the second value is strictly less than than the first value in + * terms of their mapped B results; otherwise, return false. + * + * @param the value type + * @see LT + * @see LTBy + * @see GTWith + */ +public final class LTWith implements Fn3, A, A, Boolean> { + + private static final LTWith INSTANCE = new LTWith<>(); + + private LTWith() { + } + + @Override + public BiPredicate apply(Comparator compareFn) { + return Fn3.super.apply(compareFn)::apply; + } + + @Override + public Predicate apply(Comparator compareFn, A x) { + return predicate(Fn3.super.apply(compareFn, x)); + } + + @SuppressWarnings("unchecked") + public static LTWith ltWith() { + return (LTWith) INSTANCE; + } + + public static BiPredicate ltWith(Comparator comparator) { + return LTWith.ltWith().apply(comparator); + } + + public static Predicate ltWith(Comparator comparator, A y) { + return LTWith.ltWith(comparator).apply(y); + } + + public static Boolean ltWith(Comparator comparator, A y, A x) { + return ltWith(comparator, y).apply(x); + } + + @Override + public Boolean checkedApply(Comparator comparator, A a, A a2) { + return compare(comparator, a, a2).equals(lessThan()); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelation.java b/src/main/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelation.java new file mode 100644 index 000000000..3878f385a --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelation.java @@ -0,0 +1,89 @@ +package com.jnape.palatable.lambda.functions.ordering; + +import com.jnape.palatable.lambda.adt.coproduct.CoProduct3; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.builtin.fn3.Compare; + +import java.util.Comparator; + +/** + * Specialized {@link CoProduct3} representing the possible results of a ordered comparison. + * Used by {@link Compare} as the result of a comparison. + * + * @see Compare + */ +public abstract class ComparisonRelation + implements CoProduct3 { + private ComparisonRelation() { } + + /** + * Return a comparison relation from the result of a {@link Comparator} or {@link Comparable} result + * + * @param signifier The result of {@link Comparator#compare(Object, Object)} or {@link Comparable#compareTo(Object)} + * @return The intended {@link ComparisonRelation} of the signifier + */ + public static ComparisonRelation fromInt(int signifier) { + return signifier > 0 ? greaterThan() : signifier == 0 ? equal() : lessThan(); + } + + public static GreaterThan greaterThan() { + return GreaterThan.INSTANCE; + } + + public static LessThan lessThan() { + return LessThan.INSTANCE; + } + + public static Equal equal() { + return Equal.INSTANCE; + } + + public final static class LessThan extends ComparisonRelation { + private static final LessThan INSTANCE = new LessThan(); + + private LessThan() { + } + + @Override + public String toString() { + return "LessThan"; + } + + @Override + public R match(Fn1 aFn, Fn1 bFn, Fn1 cFn) { + return aFn.apply(this); + } + } + + public final static class Equal extends ComparisonRelation { + private static final Equal INSTANCE = new Equal(); + + private Equal() { + } + + public String toString() { + return "Equal"; + } + + @Override + public R match(Fn1 aFn, Fn1 bFn, Fn1 cFn) { + return bFn.apply(this); + } + } + + public final static class GreaterThan extends ComparisonRelation { + private static final GreaterThan INSTANCE = new GreaterThan(); + + private GreaterThan() { } + + @Override + public String toString() { + return "GreaterThan"; + } + + @Override + public R match(Fn1 aFn, Fn1 bFn, Fn1 cFn) { + return cFn.apply(this); + } + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java index 78d361ba8..2abee980e 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxBy.java @@ -18,6 +18,7 @@ * @param the value type * @param the mapped comparison type * @see Max + * @see MaxWith * @see MinBy */ public final class MaxBy> implements SemigroupFactory, A> { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxWith.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxWith.java new file mode 100644 index 000000000..ed3f07373 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MaxWith.java @@ -0,0 +1,52 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import java.util.Comparator; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTWith.ltWith; + +/** + * Given a comparator for some type A, produce a {@link Semigroup} over A that chooses + * between two values x and y via the following rules: + *
    + *
  • If x is strictly less than y in terms of B, return y
  • + *
  • Otherwise, return x
  • + *
+ * + * @param
the value type + * @see Max + * @see MaxBy + * @see MinWith + */ +public final class MaxWith implements SemigroupFactory, A> { + + private static final MaxWith INSTANCE = new MaxWith<>(); + + private MaxWith() { + } + + @SuppressWarnings("unchecked") + public static MaxWith maxWith() { + return (MaxWith) INSTANCE; + } + + public static Semigroup maxWith(Comparator compareFn) { + return MaxWith.maxWith().apply(compareFn); + } + + public static Fn1 maxWith(Comparator compareFn, A x) { + return MaxWith.maxWith(compareFn).apply(x); + } + + public static A maxWith(Comparator compareFn, A x, A y) { + return maxWith(compareFn, x).apply(y); + } + + @Override + public Semigroup checkedApply(Comparator comparator) { + return (x, y) -> ltWith(comparator, y, x) ? y : x; + } +} \ No newline at end of file diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinWith.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinWith.java new file mode 100644 index 000000000..05eec2528 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/MinWith.java @@ -0,0 +1,52 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.semigroup.Semigroup; + +import java.util.Comparator; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTWith.gtWith; + +/** + * Given a comparator for some type A, produce a {@link Semigroup} over A that chooses + * between two values x and y via the following rules: + *
    + *
  • If x is strictly greater than y in terms of B, return y
  • + *
  • Otherwise, return x
  • + *
+ * + * @param
the value type + * @see Min + * @see MinBy + * @see MaxBy + */ +public final class MinWith implements SemigroupFactory, A> { + + private static final MinWith INSTANCE = new MinWith<>(); + + private MinWith() { + } + + @SuppressWarnings("unchecked") + public static MinWith minWith() { + return (MinWith) INSTANCE; + } + + public static Semigroup minWith(Comparator compareFn) { + return MinWith.minWith().apply(compareFn); + } + + public static Fn1 minWith(Comparator compareFn, A x) { + return MinWith.minWith(compareFn).apply(x); + } + + public static A minWith(Comparator compareFn, A x, A y) { + return minWith(compareFn, x).apply(y); + } + + @Override + public Semigroup checkedApply(Comparator comparator) { + return (x, y) -> gtWith(comparator, y, x) ? y : x; + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWithTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWithTest.java new file mode 100644 index 000000000..8d062f8fd --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWithTest.java @@ -0,0 +1,19 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; +import static com.jnape.palatable.lambda.functions.builtin.fn3.CmpEqBy.cmpEqBy; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class CmpEqWithTest { + @Test + public void comparisons() { + assertTrue(cmpEqBy(id(), 1, 1)); + assertFalse(cmpEqBy(id(), 1, 2)); + assertFalse(cmpEqBy(id(), 2, 1)); + + assertTrue(cmpEqBy(String::length, "b", "a")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CompareTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CompareTest.java new file mode 100644 index 000000000..8817f94fc --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/CompareTest.java @@ -0,0 +1,19 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.Compare.compare; +import static com.jnape.palatable.lambda.functions.ordering.ComparisonRelation.equal; +import static com.jnape.palatable.lambda.functions.ordering.ComparisonRelation.greaterThan; +import static com.jnape.palatable.lambda.functions.ordering.ComparisonRelation.lessThan; +import static java.util.Comparator.naturalOrder; +import static org.junit.Assert.assertEquals; + +public class CompareTest { + @Test + public void comparisons() { + assertEquals(equal(), compare(naturalOrder(), 1, 1)); + assertEquals(lessThan(), compare(naturalOrder(), 2, 1)); + assertEquals(greaterThan(), compare(naturalOrder(), 1, 2)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWithTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWithTest.java new file mode 100644 index 000000000..4ccaac4ec --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWithTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTEWith.gteWith; +import static java.util.Comparator.comparing; +import static java.util.Comparator.naturalOrder; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GTEWithTest { + @Test + public void comparisons() { + assertTrue(gteWith(naturalOrder(), 1, 2)); + assertTrue(gteWith(naturalOrder(), 1, 1)); + assertFalse(gteWith(naturalOrder(), 2, 1)); + + assertTrue(gteWith(comparing(String::length), "b", "ab")); + assertTrue(gteWith(comparing(String::length), "bc", "ab")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTWithTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTWithTest.java new file mode 100644 index 000000000..4520ee272 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTWithTest.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.GTWith.gtWith; +import static java.util.Comparator.comparing; +import static java.util.Comparator.naturalOrder; +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; + +public class GTWithTest { + @Test + public void comparisons() { + assertTrue(gtWith(naturalOrder(), 1, 2)); + assertFalse(gtWith(naturalOrder(), 1, 1)); + assertFalse(gtWith(naturalOrder(), 2, 1)); + + assertTrue(gtWith(comparing(String::length), "bb", "aaa")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWithTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWithTest.java new file mode 100644 index 000000000..18f749c16 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWithTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTEWith.lteWith; +import static java.util.Comparator.comparing; +import static java.util.Comparator.naturalOrder; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class LTEWithTest { + @Test + public void comparisons() { + assertTrue(lteWith(naturalOrder(), 2, 1)); + assertTrue(lteWith(naturalOrder(), 1, 1)); + assertFalse(lteWith(naturalOrder(), 1, 2)); + + assertTrue(lteWith(comparing(String::length), "ab", "b")); + assertTrue(lteWith(comparing(String::length), "ab", "bc")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTWithTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTWithTest.java new file mode 100644 index 000000000..dacdfd2ff --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTWithTest.java @@ -0,0 +1,20 @@ +package com.jnape.palatable.lambda.functions.builtin.fn3; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.builtin.fn3.LTWith.ltWith; +import static java.util.Comparator.comparing; +import static java.util.Comparator.naturalOrder; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class LTWithTest { + @Test + public void comparisons() { + assertTrue(ltWith(naturalOrder(), 2, 1)); + assertFalse(ltWith(naturalOrder(), 1, 1)); + assertFalse(ltWith(naturalOrder(), 1, 2)); + + assertTrue(ltWith(comparing(String::length), "ab", "b")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelationTest.java b/src/test/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelationTest.java new file mode 100644 index 000000000..8b0083661 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelationTest.java @@ -0,0 +1,23 @@ +package com.jnape.palatable.lambda.functions.ordering; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.ordering.ComparisonRelation.equal; +import static com.jnape.palatable.lambda.functions.ordering.ComparisonRelation.greaterThan; +import static com.jnape.palatable.lambda.functions.ordering.ComparisonRelation.lessThan; +import static java.lang.Integer.MAX_VALUE; +import static java.lang.Integer.MIN_VALUE; +import static org.junit.Assert.assertEquals; + +public class ComparisonRelationTest { + @Test + public void fromInt() { + assertEquals(greaterThan(), ComparisonRelation.fromInt(1)); + assertEquals(greaterThan(), ComparisonRelation.fromInt(MAX_VALUE)); + + assertEquals(equal(), ComparisonRelation.fromInt(0)); + + assertEquals(lessThan(), ComparisonRelation.fromInt(-1)); + assertEquals(lessThan(), ComparisonRelation.fromInt(MIN_VALUE)); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxWithTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxWithTest.java new file mode 100644 index 000000000..49211aee0 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MaxWithTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.semigroup.builtin.MaxWith.maxWith; +import static java.util.Comparator.comparing; +import static java.util.Comparator.naturalOrder; +import static org.junit.Assert.assertEquals; + +public class MaxWithTest { + @Test + public void semigroup() { + assertEquals((Integer) 1, maxWith(naturalOrder(), 1, 0)); + assertEquals((Integer) 1, maxWith(naturalOrder(), 1, 1)); + assertEquals((Integer) 2, maxWith(naturalOrder(), 1, 2)); + + assertEquals("ab", maxWith(comparing(String::length), "ab", "a")); + assertEquals("ab", maxWith(comparing(String::length), "ab", "cd")); + assertEquals("bc", maxWith(comparing(String::length), "a", "bc")); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinWithTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinWithTest.java new file mode 100644 index 000000000..e6bfb82bb --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/MinWithTest.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.semigroup.builtin; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.semigroup.builtin.MinWith.minWith; +import static java.util.Comparator.comparing; +import static java.util.Comparator.naturalOrder; +import static org.junit.Assert.assertEquals; + +public class MinWithTest { + @Test + public void semigroup() { + assertEquals((Integer) 1, minWith(naturalOrder(), 1, 2)); + assertEquals((Integer) 1, minWith(naturalOrder(), 1, 1)); + assertEquals((Integer) 0, minWith(naturalOrder(), 1, 0)); + + assertEquals("a", minWith(comparing(String::length), "a", "ab")); + assertEquals("ab", minWith(comparing(String::length), "ab", "cd")); + assertEquals("c", minWith(comparing(String::length), "ab", "c")); + } +} \ No newline at end of file From 4111f73fe9c3e288554031a3654e1c84d569143a Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 18 Nov 2019 11:35:46 -0600 Subject: [PATCH 282/348] Adding WriterTMatcher and WriterT#evalT/execT --- .../monad/transformer/builtin/WriterT.java | 26 +++++- .../transformer/builtin/WriterTTest.java | 44 ++++++---- .../testsupport/matchers/WriterTMatcher.java | 81 +++++++++++++++++++ 3 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 src/test/java/testsupport/matchers/WriterTMatcher.java diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java index aae118a15..7a0205543 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java @@ -46,13 +46,37 @@ private WriterT(Fn1, ? extends MonadRec, M>> writ * accumulation and the result inside the {@link Monad}. * * @param monoid the accumulation {@link Monoid} - * @param the inferred {@link Monad} result + * @param the inferred {@link MonadRec} result * @return the accumulation with the result */ public , M>> MAW runWriterT(Monoid monoid) { return writerFn.apply(monoid).coerce(); } + /** + * Given a {@link Monoid} for the accumulation, run the computation represented by this {@link WriterT} inside the + * {@link Monad monadic effect}, ignoring the resulting accumulation, yielding the value in isolation. + * + * @param monoid the accumulation {@link Monoid} + * @param the inferred {@link MonadRec} result + * @return the result + */ + public > MA evalWriterT(Monoid monoid) { + return runWriterT(monoid).fmap(Tuple2::_1).coerce(); + } + + /** + * Given a {@link Monoid} for the accumulation, run the computation represented by this {@link WriterT} inside the + * {@link Monad monadic effect}, ignoring the value, yielding the accumulation in isolation. + * + * @param monoid the accumulation {@link Monoid} + * @param the inferred {@link MonadRec} accumulation + * @return the accumulation + */ + public > MW execWriterT(Monoid monoid) { + return runWriterT(monoid).fmap(Tuple2::_2).coerce(); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java index 932fe7011..c1caa0527 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterTTest.java @@ -25,7 +25,11 @@ import static com.jnape.palatable.lambda.monad.transformer.builtin.WriterT.writerT; import static com.jnape.palatable.lambda.monoid.builtin.Join.join; import static com.jnape.palatable.lambda.monoid.builtin.Trivial.trivial; -import static org.junit.Assert.assertEquals; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.WriterTMatcher.whenEvaluatedWith; +import static testsupport.matchers.WriterTMatcher.whenExecutedWith; +import static testsupport.matchers.WriterTMatcher.whenRunWith; import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) @@ -38,38 +42,46 @@ public Equivalence, Integer>> testSubject() { @Test public void accumulationUsesProvidedMonoid() { - Identity> result = writerT(new Identity<>(tuple(1, "foo"))) - .discardR(WriterT.tell(new Identity<>("bar"))) - .flatMap(x -> writerT(new Identity<>(tuple(x + 1, "baz")))) - .runWriterT(join()); + assertThat(writerT(new Identity<>(tuple(1, "foo"))) + .discardR(WriterT.tell(new Identity<>("bar"))) + .flatMap(x -> writerT(new Identity<>(tuple(x + 1, "baz")))), + whenRunWith(join(), equalTo(new Identity<>(tuple(2, "foobarbaz"))))); + } - assertEquals(new Identity<>(tuple(2, "foobarbaz")), result); + @Test + public void eval() { + assertThat(writerT(new Identity<>(tuple(1, "foo"))), + whenEvaluatedWith(join(), equalTo(new Identity<>(1)))); + } + + @Test + public void exec() { + assertThat(writerT(new Identity<>(tuple(1, "foo"))), + whenExecutedWith(join(), equalTo(new Identity<>("foo")))); } @Test public void tell() { - assertEquals(new Identity<>(tuple(UNIT, "")), - WriterT.tell(new Identity<>("")).runWriterT(join())); + assertThat(WriterT.tell(new Identity<>("")), + whenRunWith(join(), equalTo(new Identity<>(tuple(UNIT, ""))))); } @Test public void listen() { - assertEquals(new Identity<>(tuple(1, "")), - WriterT., Integer>listen(new Identity<>(1)).runWriterT(join())); + assertThat(WriterT.listen(new Identity<>(1)), + whenRunWith(join(), equalTo(new Identity<>(tuple(1, ""))))); } @Test public void staticPure() { - WriterT, Integer> apply = WriterT.>pureWriterT(pureIdentity()).apply(1); - assertEquals(new Identity<>(tuple(1, "")), - apply.runWriterT(join())); + assertThat(WriterT.>pureWriterT(pureIdentity()).apply(1), + whenRunWith(join(), equalTo(new Identity<>(tuple(1, ""))))); } @Test public void staticLift() { - WriterT, Integer> apply = WriterT.liftWriterT().apply(new Identity<>(1)); - assertEquals(new Identity<>(tuple(1, "")), - apply.runWriterT(join())); + assertThat(WriterT.liftWriterT().apply(new Identity<>(1)), + whenRunWith(join(), equalTo(new Identity<>(tuple(1, ""))))); } @Test(timeout = 500) diff --git a/src/test/java/testsupport/matchers/WriterTMatcher.java b/src/test/java/testsupport/matchers/WriterTMatcher.java new file mode 100644 index 000000000..36e2786bb --- /dev/null +++ b/src/test/java/testsupport/matchers/WriterTMatcher.java @@ -0,0 +1,81 @@ +package testsupport.matchers; + +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.transformer.builtin.WriterT; +import com.jnape.palatable.lambda.monoid.Monoid; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +public final class WriterTMatcher, A> extends + TypeSafeMatcher>> { + + private final Matcher, M>> expected; + private final Monoid wMonoid; + + private WriterTMatcher(Matcher, M>> expected, Monoid wMonoid) { + this.wMonoid = wMonoid; + this.expected = expected; + } + + @Override + protected boolean matchesSafely(MonadRec> item) { + return expected.matches(item.>coerce().runWriterT(wMonoid)); + } + + @Override + public void describeTo(Description description) { + expected.describeTo(description); + } + + @Override + protected void describeMismatchSafely(MonadRec> item, Description mismatchDescription) { + expected.describeMismatch(item.>coerce().runWriterT(wMonoid), mismatchDescription); + } + + public static , A, MAW extends MonadRec, M>> + WriterTMatcher whenRunWith(Monoid wMonoid, Matcher matcher) { + return new WriterTMatcher<>(matcher, wMonoid); + } + + public static , A, MW extends MonadRec> + WriterTMatcher whenExecutedWith(Monoid wMonoid, Matcher matcher) { + return whenRunWith(wMonoid, new TypeSafeMatcher, M>>() { + @Override + protected boolean matchesSafely(MonadRec, M> item) { + return matcher.matches(item.fmap(Tuple2::_2)); + } + + @Override + public void describeTo(Description description) { + matcher.describeTo(description); + } + + @Override + protected void describeMismatchSafely(MonadRec, M> item, Description mismatchDescription) { + matcher.describeMismatch(item.fmap(Tuple2::_2), mismatchDescription); + } + }); + } + + public static , A, MA extends MonadRec> + WriterTMatcher whenEvaluatedWith(Monoid wMonoid, Matcher matcher) { + return whenRunWith(wMonoid, new TypeSafeMatcher, M>>() { + @Override + protected boolean matchesSafely(MonadRec, M> item) { + return matcher.matches(item.fmap(Tuple2::_1)); + } + + @Override + public void describeTo(Description description) { + matcher.describeTo(description); + } + + @Override + protected void describeMismatchSafely(MonadRec, M> item, Description mismatchDescription) { + matcher.describeMismatch(item.fmap(Tuple2::_1), mismatchDescription); + } + }); + } +} \ No newline at end of file From 1a84d0fd86a886a9c4c2a626c86f68147300b63c Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Tue, 19 Nov 2019 15:16:06 -0600 Subject: [PATCH 283/348] Added MonadError instance to EitherT --- .../monad/transformer/builtin/EitherT.java | 22 ++++++++++++++++++- .../transformer/builtin/EitherTTest.java | 13 +++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java index 806fdb636..a23a81fcf 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherT.java @@ -10,6 +10,7 @@ import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadError; import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.MonadT; @@ -28,7 +29,8 @@ */ public final class EitherT, L, R> implements Bifunctor>, - MonadT, EitherT> { + MonadT, EitherT>, + MonadError> { private final MonadRec, M> melr; @@ -120,6 +122,24 @@ public EitherT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } + /** + * {@inheritDoc} + */ + @Override + public EitherT throwError(L l) { + return eitherT(melr.pure(left(l))); + } + + /** + * {@inheritDoc} + */ + @Override + public EitherT catchError(Fn1>> recoveryFn) { + return eitherT(runEitherT().flatMap(e -> e.match( + l -> recoveryFn.apply(l).>coerce().runEitherT(), + r -> melr.pure(r).fmap(Either::right)))); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java index cefc21eda..520a350b4 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -27,6 +28,7 @@ import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.eitherT; import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.liftEitherT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.pureEitherT; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -73,4 +75,15 @@ public void staticPure() { .apply(1); assertEquals(eitherT(new Identity<>(right(1))), eitherT); } + + @Test + public void monadError() { + Pure, String, ?>> pure = pureEitherT(pureIdentity()); + + assertEquals(eitherT(new Identity<>(left("Hello"))), + pure., String, Integer>>apply(1).throwError("Hello")); + assertEquals(pure.apply(5), + EitherT., String, Integer>eitherT(new Identity<>(left("Hello"))) + .catchError(s -> pure.apply(s.length()))); + } } \ No newline at end of file From 0c5f7e2de8d9077becf0ec032e0637bb94b3089b Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 1 Dec 2019 17:00:02 -0600 Subject: [PATCH 284/348] Leveraging MonadErrorAssert in EitherTTest --- .../monad/transformer/builtin/EitherTTest.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java index 520a350b4..e495fb2fd 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/EitherTTest.java @@ -2,7 +2,6 @@ import com.jnape.palatable.lambda.adt.Either; import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -28,9 +27,9 @@ import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.eitherT; import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.liftEitherT; -import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.pureEitherT; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; +import static testsupport.assertion.MonadErrorAssert.assertLaws; @RunWith(Traits.class) public class EitherTTest { @@ -78,12 +77,9 @@ public void staticPure() { @Test public void monadError() { - Pure, String, ?>> pure = pureEitherT(pureIdentity()); - - assertEquals(eitherT(new Identity<>(left("Hello"))), - pure., String, Integer>>apply(1).throwError("Hello")); - assertEquals(pure.apply(5), - EitherT., String, Integer>eitherT(new Identity<>(left("Hello"))) - .catchError(s -> pure.apply(s.length()))); + assertLaws(subjects(eitherT(new Identity<>(right(1))), + eitherT(new Identity<>(left("")))), + "bar", + str -> eitherT(new Identity<>(right(str.length())))); } } \ No newline at end of file From ebce62cdadc1c925a1961a9f8030a415f85acb9c Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 10 Dec 2019 14:26:11 -0600 Subject: [PATCH 285/348] Updating CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 488f8b414..1afe4208b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - `HList#cons` static factory method auto-promotes to specialized `HList` if there is one +- `EitherT` gains a `MonadError` instance ### Added - `MergeHMaps`, a `Monoid` that merges `HMap`s by merging the values via key-specified `Semigroup`s From 5cb722b8e640c444eabc6218977ecaa407210b06 Mon Sep 17 00:00:00 2001 From: Michael A Date: Mon, 2 Dec 2019 08:38:04 -0600 Subject: [PATCH 286/348] Added StateT and State matchers --- .../lambda/matchers/StateMatcherTest.java | 34 ++++++ .../lambda/matchers/StateTMatcherTest.java | 56 +++++++++ .../monad/transformer/builtin/StateTTest.java | 85 ++++++------- .../testsupport/matchers/StateMatcher.java | 90 ++++++++++++++ .../testsupport/matchers/StateTMatcher.java | 114 ++++++++++++++++++ 5 files changed, 331 insertions(+), 48 deletions(-) create mode 100644 src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java create mode 100644 src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java create mode 100644 src/test/java/testsupport/matchers/StateMatcher.java create mode 100644 src/test/java/testsupport/matchers/StateTMatcher.java diff --git a/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java b/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java new file mode 100644 index 000000000..fb27f6f78 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java @@ -0,0 +1,34 @@ +package com.jnape.palatable.lambda.matchers; + +import com.jnape.palatable.lambda.adt.Either; +import org.junit.Test; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.functor.builtin.State.state; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static testsupport.matchers.LeftMatcher.isLeftThat; +import static testsupport.matchers.RightMatcher.isRightThat; +import static testsupport.matchers.StateMatcher.*; + +public class StateMatcherTest { + + @Test + public void whenEvalWithMatcher() { + assertThat(state(Either.right(1)), + whenEvaluatedWith("0", isRightThat(equalTo(1)))); + } + + @Test + public void whenExecWithMatcher() { + assertThat(state(Either.right(1)), + whenExecutedWith(left("0"), isLeftThat(equalTo("0")))); + } + + @Test + public void whenRunWithMatcher() { + assertThat(state(Either.right(1)), + whenRunWith(left("0"), isRightThat(equalTo(1)), isLeftThat(equalTo("0")))); + } + +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java new file mode 100644 index 000000000..a54a0c19b --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java @@ -0,0 +1,56 @@ +package com.jnape.palatable.lambda.matchers; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.monad.transformer.builtin.StateT; +import org.junit.Test; +import testsupport.matchers.StateTMatcher; + +import java.util.concurrent.atomic.AtomicInteger; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.stateT; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertEquals; +import static testsupport.matchers.IOMatcher.yieldsValue; +import static testsupport.matchers.LeftMatcher.isLeftThat; +import static testsupport.matchers.RightMatcher.isRightThat; +import static testsupport.matchers.StateTMatcher.*; + +public class StateTMatcherTest { + + @Test + public void whenEvalWithMatcher() { + assertThat(stateT(Either.right(1)), + StateTMatcher.whenEvaluatedWith("0", isRightThat(equalTo(1)))); + } + + @Test + public void whenExecWithMatcher() { + assertThat(stateT(Either.right(1)), + whenExecutedWith(left("0"), isRightThat(isLeftThat(equalTo("0"))))); + } + + @Test + public void whenRunWithUsingTwoMatchers() { + assertThat(stateT(Either.right(1)), + whenRunWith(left("0"), isRightThat(equalTo(1)), isRightThat(isLeftThat(equalTo("0"))))); + } + + @Test + public void whenRunWithUsingOneTupleMatcher() { + assertThat(stateT(Either.right(1)), + whenRunWith(left("0"), isRightThat(equalTo(tuple(1, left("0")))))); + } + + @Test + public void onlyRunsStateOnceWithTupleMatcher() { + AtomicInteger count = new AtomicInteger(0); + + assertThat(StateT.gets(s -> io(count::incrementAndGet)), + whenRunWith(0, yieldsValue(equalTo(tuple(1, 0))))); + assertEquals(1, count.get()); + } +} \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java index b30fd4596..967947052 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java @@ -1,6 +1,5 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; -import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.builtin.Identity; @@ -8,13 +7,7 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.traits.ApplicativeLaws; -import testsupport.traits.Equivalence; -import testsupport.traits.FunctorLaws; -import testsupport.traits.MonadLaws; -import testsupport.traits.MonadReaderLaws; -import testsupport.traits.MonadRecLaws; -import testsupport.traits.MonadWriterLaws; +import testsupport.traits.*; import java.util.ArrayList; import java.util.List; @@ -26,18 +19,19 @@ import static com.jnape.palatable.lambda.optics.functions.Set.set; import static com.jnape.palatable.lambda.optics.lenses.ListLens.elementAt; import static java.util.Arrays.asList; -import static org.junit.Assert.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; +import static testsupport.matchers.StateTMatcher.*; import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class StateTTest { @TestTraits({FunctorLaws.class, - ApplicativeLaws.class, - MonadLaws.class, - MonadRecLaws.class, - MonadReaderLaws.class, - MonadWriterLaws.class}) + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + MonadReaderLaws.class, + MonadWriterLaws.class}) public Equivalence, Integer>> testReader() { return equivalence(StateT.gets(s -> new Identity<>(s.length())), s -> s.runStateT("foo")); } @@ -47,85 +41,80 @@ public void evalAndExec() { StateT, Integer> stateT = StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_"))); - assertEquals(new Identity<>("__"), stateT.execT("_")); - assertEquals(new Identity<>(1), stateT.evalT("_")); + assertThat(stateT, whenExecuted("_", new Identity<>("__"))); + assertThat(stateT, whenEvaluated("_", new Identity<>(1))); } @Test public void mapStateT() { StateT, Integer> stateT = StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_"))); - assertEquals(just(tuple(4, "ABC_")), - stateT.mapStateT(id -> id.>>coerce() - .runIdentity() - .into((x, str) -> just(tuple(x + 1, str.toUpperCase())))) - .>>runStateT("abc")); + + assertThat(stateT.mapStateT(id -> id.>>coerce() + .runIdentity() + .into((x, str) -> just(tuple(x + 1, str.toUpperCase())))), + whenRun("abc", just(tuple(4, "ABC_")))); } @Test public void zipping() { - Tuple2> result = StateT., Identity>modify( + StateT, Identity, Unit> result = StateT., Identity>modify( s -> new Identity<>(set(elementAt(s.size()), just("one"), s))) - .discardL(StateT.modify(s -> new Identity<>(set(elementAt(s.size()), just("two"), s)))) - .>>>runStateT(new ArrayList<>()) - .runIdentity(); + .discardL(StateT.modify(s -> new Identity<>(set(elementAt(s.size()), just("two"), s)))); - assertEquals(tuple(UNIT, asList("one", "two")), - result); + assertThat(result, + whenRun(new ArrayList<>(), new Identity<>(tuple(UNIT, asList("one", "two"))))); } @Test public void withStateT() { StateT, Integer> stateT = StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_"))); - assertEquals(new Identity<>(tuple(3, "ABC_")), - stateT.withStateT(str -> new Identity<>(str.toUpperCase())).runStateT("abc")); + assertThat(stateT.withStateT(str -> new Identity<>(str.toUpperCase())), + whenRun("abc", new Identity<>(tuple(3, "ABC_")))); } @Test public void get() { - assertEquals(new Identity<>(tuple("state", "state")), - StateT.>get(pureIdentity()).runStateT("state")); + assertThat(StateT.get(pureIdentity()), + whenRun("state", new Identity<>(tuple("state", "state")))); } @Test public void gets() { - assertEquals(new Identity<>(tuple(5, "state")), - StateT., Integer>gets(s -> new Identity<>(s.length())).runStateT("state")); + assertThat(StateT.gets(s -> new Identity<>(s.length())), + whenRun("state", new Identity<>(tuple(5, "state")))); } @Test public void put() { - assertEquals(new Identity<>(tuple(UNIT, 1)), StateT.put(new Identity<>(1)).runStateT(0)); + assertThat(StateT.put(new Identity<>(1)), + whenRun(0, new Identity<>(tuple(UNIT, 1)))); } @Test public void modify() { - assertEquals(new Identity<>(tuple(UNIT, 1)), - StateT.>modify(x -> new Identity<>(x + 1)).runStateT(0)); + assertThat(StateT.modify(x -> new Identity<>(x + 1)), + whenRun(0, new Identity<>(tuple(UNIT, 1)))); } @Test public void stateT() { - assertEquals(new Identity<>(tuple(0, "_")), - StateT., Integer>stateT(new Identity<>(0)).runStateT("_")); - assertEquals(new Identity<>(tuple(1, "_1")), - StateT., Integer>stateT(s -> new Identity<>(tuple(s.length(), s + "1"))) - .runStateT("_")); + assertThat(StateT.stateT(new Identity<>(0)), + whenRun("_", new Identity<>(tuple(0, "_")))); + assertThat(StateT.stateT(s -> new Identity<>(tuple(s.length(), s + "1"))), + whenRun("_", new Identity<>(tuple(1, "_1")))); } @Test public void staticPure() { - assertEquals(new Identity<>(tuple(1, "foo")), - StateT.>pureStateT(pureIdentity()) - ., Integer>>apply(1) - .>>runStateT("foo")); + assertThat(StateT.>pureStateT(pureIdentity()).apply(1), + whenRun("foo", new Identity<>(tuple(1, "foo")))); } @Test public void staticLift() { - assertEquals(new Identity<>(tuple(1, "foo")), - StateT.liftStateT()., StateT, Integer>>apply(new Identity<>(1)) - .>>runStateT("foo")); + assertThat(StateT.liftStateT().apply(new Identity<>(1)), + whenRun("foo", new Identity<>(tuple(1, "foo")))); } } \ No newline at end of file diff --git a/src/test/java/testsupport/matchers/StateMatcher.java b/src/test/java/testsupport/matchers/StateMatcher.java new file mode 100644 index 000000000..4f23594f3 --- /dev/null +++ b/src/test/java/testsupport/matchers/StateMatcher.java @@ -0,0 +1,90 @@ +package testsupport.matchers; + +import com.jnape.palatable.lambda.adt.These; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functor.builtin.State; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import static com.jnape.palatable.lambda.adt.These.*; +import static com.jnape.palatable.lambda.io.IO.io; +import static org.hamcrest.Matchers.equalTo; + +public class StateMatcher extends TypeSafeMatcher> { + private final S initialState; + private final These, Matcher> matchers; + + private StateMatcher(S initialState, These, Matcher> matchers) { + this.initialState = initialState; + this.matchers = matchers; + } + + @Override + protected boolean matchesSafely(State item) { + Tuple2 ran = item.run(initialState); + return matchers.match(a -> a.matches(ran._1()), + b -> b.matches(ran._2()), + ab -> ab._1().matches(ran._1()) && ab._2().matches(ran._2())); + } + + @Override + public void describeTo(Description description) { + matchers.match(a -> io(() -> a.describeTo(description.appendText("Value matching "))), + b -> io(() -> b.describeTo(description.appendText("State matching "))), + ab -> io(() -> { + description.appendText("Value matching: "); + ab._1().describeTo(description); + description.appendText(" and state matching: "); + ab._2().describeTo(description); + })) + .unsafePerformIO(); + } + + @Override + protected void describeMismatchSafely(State item, Description mismatchDescription) { + Tuple2 ran = item.run(initialState); + matchers.match(a -> io(() -> { + mismatchDescription.appendText("value matching "); + a.describeMismatch(ran._1(), mismatchDescription); + }), + b -> io(() -> { + mismatchDescription.appendText("state matching "); + b.describeMismatch(ran._2(), mismatchDescription); + }), + ab -> io(() -> { + mismatchDescription.appendText("value matching: "); + ab._1().describeMismatch(ran._1(), mismatchDescription); + mismatchDescription.appendText(" and state matching: "); + ab._2().describeMismatch(ran._2(), mismatchDescription); + })) + .unsafePerformIO(); + } + + public static StateMatcher whenRunWith(S initialState, Matcher valueMatcher, Matcher stateMatcher) { + return new StateMatcher<>(initialState, both(valueMatcher, stateMatcher)); + } + + @SuppressWarnings("unused") + public static StateMatcher whenRun(S initialState, A value, S state) { + return whenRunWith(initialState, equalTo(value), equalTo(state)); + } + + public static StateMatcher whenExecutedWith(S initialState, Matcher stateMatcher) { + return new StateMatcher<>(initialState, b(stateMatcher)); + } + + @SuppressWarnings("unused") + public static StateMatcher whenExecuted(S initialState, S state) { + return whenExecutedWith(initialState, equalTo(state)); + } + + public static StateMatcher whenEvaluatedWith(S initialState, Matcher valueMatcher) { + return new StateMatcher<>(initialState, a(valueMatcher)); + } + + @SuppressWarnings("unused") + public static StateMatcher whenEvaluated(S initialState, A value) { + return whenEvaluatedWith(initialState, equalTo(value)); + } +} diff --git a/src/test/java/testsupport/matchers/StateTMatcher.java b/src/test/java/testsupport/matchers/StateTMatcher.java new file mode 100644 index 000000000..944b60f43 --- /dev/null +++ b/src/test/java/testsupport/matchers/StateTMatcher.java @@ -0,0 +1,114 @@ +package testsupport.matchers; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.These; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.transformer.builtin.StateT; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.io.IO.io; +import static org.hamcrest.Matchers.equalTo; + +public class StateTMatcher, A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> extends TypeSafeMatcher> { + private final S initialState; + + private final Either, These, Matcher>> matcher; + + private StateTMatcher(S initialState, These, Matcher> matchers) { + this.initialState = initialState; + this.matcher = right(matchers); + } + + private StateTMatcher(S initialState, Matcher matcher) { + this.initialState = initialState; + this.matcher = left(matcher); + } + + @Override + protected boolean matchesSafely(StateT item) { + MonadRec, M> ran = item.runStateT(initialState); + return matcher.match(bothMatcher -> bothMatcher.matches(ran), + theseMatchers -> theseMatchers.match(a -> a.matches(ran.fmap(Tuple2::_1)), + b -> b.matches(ran.fmap(Tuple2::_2)), + ab -> ab._1().matches(ran.fmap(Tuple2::_1)) && ab._2().matches(ran.fmap(Tuple2::_2)))); + } + + @Override + public void describeTo(Description description) { + matcher.match(bothMatcher -> io(() -> bothMatcher.describeTo(description.appendText("Value and state matching "))), + theseMatchers -> theseMatchers.match(a -> io(() -> a.describeTo(description.appendText("Value matching "))), + b -> io(() -> b.describeTo(description.appendText("State matching "))), + ab -> io(() -> { + description.appendText("Value matching: "); + ab._1().describeTo(description); + description.appendText(" and state matching: "); + ab._2().describeTo(description); + }))) + .unsafePerformIO(); + } + + @Override + protected void describeMismatchSafely(StateT item, Description mismatchDescription) { + MonadRec, M> ran = item.runStateT(initialState); + + matcher.match(bothMatcher -> io(() -> { + mismatchDescription.appendText("value and state matching "); + bothMatcher.describeMismatch(ran, mismatchDescription); + }), + theseMatchers -> theseMatchers.match(a -> io(() -> { + mismatchDescription.appendText("value matching "); + a.describeMismatch(ran.fmap(Tuple2::_1), mismatchDescription); + }), + b -> io(() -> { + mismatchDescription.appendText("state matching "); + b.describeMismatch(ran.fmap(Tuple2::_2), mismatchDescription); + }), + ab -> io(() -> { + mismatchDescription.appendText("value matching: "); + ab._1().describeMismatch(ran.fmap(Tuple2::_1), mismatchDescription); + mismatchDescription.appendText(" and state matching: "); + ab._2().describeMismatch(ran.fmap(Tuple2::_2), mismatchDescription); + }))) + .unsafePerformIO(); + } + + public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenRunWith(S initialState, Matcher bothMatcher) { + return new StateTMatcher<>(initialState, bothMatcher); + } + + public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenRun(S initialState, MTS both) { + return whenRunWith(initialState, equalTo(both)); + } + + // Note: This constructor will run both matchers, which can run effects twice + public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenRunWith(S initialState, Matcher valueMatcher, Matcher stateMatcher) { + return new StateTMatcher<>(initialState, These.both(valueMatcher, stateMatcher)); + } + + // Note: This constructor will run both matchers, which can run effects twice + @SuppressWarnings("unused") + public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenRun(S initialState, MA value, MS state) { + return whenRunWith(initialState, equalTo(value), equalTo(state)); + } + + public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenExecutedWith(S initialState, Matcher stateMatcher) { + return new StateTMatcher<>(initialState, These.b(stateMatcher)); + } + + public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenExecuted(S initialState, MS state) { + return whenExecutedWith(initialState, equalTo(state)); + } + + public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenEvaluatedWith(S initialState, Matcher valueMatcher) { + return new StateTMatcher<>(initialState, These.a(valueMatcher)); + } + + public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenEvaluated(S initialState, MA value) { + return whenEvaluatedWith(initialState, equalTo(value)); + } +} From 2b659fbee448bac8ca570a281fc2bf1467774645 Mon Sep 17 00:00:00 2001 From: Michael A Date: Mon, 2 Dec 2019 08:51:08 -0600 Subject: [PATCH 287/348] Added type parameters to appease earlier versions of Java 8 --- .../palatable/lambda/matchers/StateTMatcherTest.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java index a54a0c19b..478a276ac 100644 --- a/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java @@ -1,6 +1,9 @@ package com.jnape.palatable.lambda.matchers; import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.builtin.StateT; import org.junit.Test; import testsupport.matchers.StateTMatcher; @@ -36,13 +39,15 @@ public void whenExecWithMatcher() { @Test public void whenRunWithUsingTwoMatchers() { assertThat(stateT(Either.right(1)), - whenRunWith(left("0"), isRightThat(equalTo(1)), isRightThat(isLeftThat(equalTo("0"))))); + StateTMatcher., Either, Integer, Either, Either>, Either>>>whenRunWith(left("0"), + isRightThat(equalTo(1)), isRightThat(isLeftThat(equalTo("0"))))); } @Test public void whenRunWithUsingOneTupleMatcher() { assertThat(stateT(Either.right(1)), - whenRunWith(left("0"), isRightThat(equalTo(tuple(1, left("0")))))); + StateTMatcher., Either, Integer, Either, Either>, Either>>>whenRunWith(left("0"), + isRightThat(equalTo(tuple(1, left("0")))))); } @Test @@ -50,7 +55,7 @@ public void onlyRunsStateOnceWithTupleMatcher() { AtomicInteger count = new AtomicInteger(0); assertThat(StateT.gets(s -> io(count::incrementAndGet)), - whenRunWith(0, yieldsValue(equalTo(tuple(1, 0))))); + StateTMatcher., Integer, IO, IO, IO>>whenRunWith(0, yieldsValue(equalTo(tuple(1, 0))))); assertEquals(1, count.get()); } } \ No newline at end of file From e3158d1f8aa06c2166f14d32a3a1e9c5c6e7f73f Mon Sep 17 00:00:00 2001 From: Michael A Date: Wed, 4 Dec 2019 15:34:12 -0600 Subject: [PATCH 288/348] Cleaned up type params; made double-run effects clearer --- .../lambda/matchers/StateTMatcherTest.java | 49 ++++++++++----- .../testsupport/matchers/StateTMatcher.java | 60 ++++++++++++------- 2 files changed, 71 insertions(+), 38 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java index 478a276ac..39a6a22b1 100644 --- a/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java @@ -1,9 +1,6 @@ package com.jnape.palatable.lambda.matchers; import com.jnape.palatable.lambda.adt.Either; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.io.IO; -import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.builtin.StateT; import org.junit.Test; import testsupport.matchers.StateTMatcher; @@ -11,9 +8,11 @@ import java.util.concurrent.atomic.AtomicInteger; import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.io.IO.io; import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.stateT; +import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertEquals; @@ -25,37 +24,57 @@ public class StateTMatcherTest { @Test - public void whenEvalWithMatcher() { - assertThat(stateT(Either.right(1)), - StateTMatcher.whenEvaluatedWith("0", isRightThat(equalTo(1)))); + public void whenEvaluatedWithMatcher() { + assertThat(stateT(right(1)), + whenEvaluatedWith("0", isRightThat(equalTo(1)))); } @Test - public void whenExecWithMatcher() { - assertThat(stateT(Either.right(1)), + public void whenEvaluatedWithMatcherOnObject() { + assertThat(stateT(right(1)), + whenEvaluatedWith("0", not(equalTo(new Object())))); + } + + @Test + public void whenExecutedWithMatcher() { + assertThat(stateT(right(1)), whenExecutedWith(left("0"), isRightThat(isLeftThat(equalTo("0"))))); } + + @Test + public void whenExecutedWithMatcherOnObject() { + assertThat(stateT(right(1)), + whenExecutedWith(left("0"), not(equalTo(new Object())))); + } + @Test public void whenRunWithUsingTwoMatchers() { - assertThat(stateT(Either.right(1)), - StateTMatcher., Either, Integer, Either, Either>, Either>>>whenRunWith(left("0"), - isRightThat(equalTo(1)), isRightThat(isLeftThat(equalTo("0"))))); + //noinspection RedundantTypeArguments + assertThat(stateT(right(1)), + StateTMatcher., Either, Integer, Either, Either>>whenRunWithBoth(left("0"), + isRightThat(equalTo(1)), + isRightThat(isLeftThat(equalTo("0"))))); } @Test public void whenRunWithUsingOneTupleMatcher() { - assertThat(stateT(Either.right(1)), - StateTMatcher., Either, Integer, Either, Either>, Either>>>whenRunWith(left("0"), + assertThat(stateT(right(1)), + whenRunWith(left("0"), isRightThat(equalTo(tuple(1, left("0")))))); } + @Test + public void whenRunWithUsingOneTupleMatcherOnObject() { + assertThat(stateT(right(1)), + whenRunWith(left("0"), not(equalTo(new Object())))); + } + @Test public void onlyRunsStateOnceWithTupleMatcher() { AtomicInteger count = new AtomicInteger(0); - assertThat(StateT.gets(s -> io(count::incrementAndGet)), - StateTMatcher., Integer, IO, IO, IO>>whenRunWith(0, yieldsValue(equalTo(tuple(1, 0))))); + assertThat(StateT.gets(s -> io(count::incrementAndGet)), whenRunWith(0, yieldsValue(equalTo(tuple(1, 0))))); assertEquals(1, count.get()); } } \ No newline at end of file diff --git a/src/test/java/testsupport/matchers/StateTMatcher.java b/src/test/java/testsupport/matchers/StateTMatcher.java index 944b60f43..39ec23899 100644 --- a/src/test/java/testsupport/matchers/StateTMatcher.java +++ b/src/test/java/testsupport/matchers/StateTMatcher.java @@ -14,17 +14,17 @@ import static com.jnape.palatable.lambda.io.IO.io; import static org.hamcrest.Matchers.equalTo; -public class StateTMatcher, A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> extends TypeSafeMatcher> { +public class StateTMatcher, A> extends TypeSafeMatcher> { private final S initialState; - private final Either, These, Matcher>> matcher; + private final Either, M>>, These>, Matcher>>> matcher; - private StateTMatcher(S initialState, These, Matcher> matchers) { + private StateTMatcher(S initialState, These>, Matcher>> matchers) { this.initialState = initialState; this.matcher = right(matchers); } - private StateTMatcher(S initialState, Matcher matcher) { + private StateTMatcher(S initialState, Matcher, M>> matcher) { this.initialState = initialState; this.matcher = left(matcher); } @@ -44,9 +44,9 @@ public void describeTo(Description description) { theseMatchers -> theseMatchers.match(a -> io(() -> a.describeTo(description.appendText("Value matching "))), b -> io(() -> b.describeTo(description.appendText("State matching "))), ab -> io(() -> { - description.appendText("Value matching: "); + description.appendText("Value run matching: "); ab._1().describeTo(description); - description.appendText(" and state matching: "); + description.appendText(", then state run matching: "); ab._2().describeTo(description); }))) .unsafePerformIO(); @@ -69,46 +69,60 @@ protected void describeMismatchSafely(StateT item, Description mismatch b.describeMismatch(ran.fmap(Tuple2::_2), mismatchDescription); }), ab -> io(() -> { - mismatchDescription.appendText("value matching: "); + mismatchDescription.appendText("value run matching: "); ab._1().describeMismatch(ran.fmap(Tuple2::_1), mismatchDescription); - mismatchDescription.appendText(" and state matching: "); + mismatchDescription.appendText(", then state run matching: "); ab._2().describeMismatch(ran.fmap(Tuple2::_2), mismatchDescription); }))) .unsafePerformIO(); } - public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenRunWith(S initialState, Matcher bothMatcher) { - return new StateTMatcher<>(initialState, bothMatcher); + public static , A, MAS extends MonadRec, M>> StateTMatcher whenRunWith(S initialState, Matcher bothMatcher) { + return new StateTMatcher(initialState, extendMatcher(bothMatcher)); } - public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenRun(S initialState, MTS both) { + public static , A> StateTMatcher whenRun(S initialState, MonadRec, M> both) { return whenRunWith(initialState, equalTo(both)); } - // Note: This constructor will run both matchers, which can run effects twice - public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenRunWith(S initialState, Matcher valueMatcher, Matcher stateMatcher) { - return new StateTMatcher<>(initialState, These.both(valueMatcher, stateMatcher)); + // Note: This constructor will run both matchers, which will run effects twice + public static , A, MA extends MonadRec, MS extends MonadRec> StateTMatcher whenRunWithBoth(S initialState, Matcher valueMatcher, Matcher stateMatcher) { + return new StateTMatcher(initialState, These.both(extendMatcher(valueMatcher), extendMatcher(stateMatcher))); } - // Note: This constructor will run both matchers, which can run effects twice + // Note: This constructor will run both matchers, which will run effects twice @SuppressWarnings("unused") - public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenRun(S initialState, MA value, MS state) { - return whenRunWith(initialState, equalTo(value), equalTo(state)); + public static , A, MA extends MonadRec, MS extends MonadRec> StateTMatcher whenRunBoth(S initialState, MonadRec value, MonadRec state) { + return whenRunWithBoth(initialState, equalTo(value), equalTo(state)); } - public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenExecutedWith(S initialState, Matcher stateMatcher) { - return new StateTMatcher<>(initialState, These.b(stateMatcher)); + public static , A, MS extends MonadRec> StateTMatcher whenExecutedWith(S initialState, Matcher stateMatcher) { + return new StateTMatcher(initialState, These.b(extendMatcher(stateMatcher))); } - public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenExecuted(S initialState, MS state) { + public static , A> StateTMatcher whenExecuted(S initialState, MonadRec state) { return whenExecutedWith(initialState, equalTo(state)); } - public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenEvaluatedWith(S initialState, Matcher valueMatcher) { - return new StateTMatcher<>(initialState, These.a(valueMatcher)); + public static , A, MA extends MonadRec> StateTMatcher whenEvaluatedWith(S initialState, Matcher valueMatcher) { + return new StateTMatcher(initialState, These.a(extendMatcher(valueMatcher))); } - public static , A, MA extends MonadRec, MS extends MonadRec, MTS extends MonadRec, M>> StateTMatcher whenEvaluated(S initialState, MA value) { + public static , A> StateTMatcher whenEvaluated(S initialState, MonadRec value) { return whenEvaluatedWith(initialState, equalTo(value)); } + + private static , MX extends MonadRec> Matcher> extendMatcher(Matcher matcher) { + return new TypeSafeMatcher>() { + @Override + protected boolean matchesSafely(MonadRec item) { + return matcher.matches(item); + } + + @Override + public void describeTo(Description description) { + matcher.describeTo(description); + } + }; + } } From e22363dff7e863fd27ae887321c1a1c2e73e1858 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 10 Dec 2019 15:21:58 -0600 Subject: [PATCH 289/348] Reformatting --- .../lambda/functor/builtin/StateTest.java | 47 +++---- .../lambda/matchers/StateMatcherTest.java | 19 +-- .../lambda/matchers/StateTMatcherTest.java | 35 ++--- .../monad/transformer/builtin/StateTTest.java | 68 +++++----- .../testsupport/matchers/StateMatcher.java | 58 ++++---- .../testsupport/matchers/StateTMatcher.java | 124 ++++++++++-------- 6 files changed, 183 insertions(+), 168 deletions(-) diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java index db591bcfa..7e86042d2 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/StateTest.java @@ -1,8 +1,5 @@ package com.jnape.palatable.lambda.functor.builtin; -import com.jnape.palatable.lambda.adt.Unit; -import com.jnape.palatable.lambda.adt.hlist.Tuple2; -import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; @@ -17,8 +14,12 @@ import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static testsupport.matchers.StateMatcher.whenEvaluated; +import static testsupport.matchers.StateMatcher.whenExecuted; +import static testsupport.matchers.StateMatcher.whenRun; import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) @@ -36,71 +37,65 @@ public Equivalence> testSubject() { @Test public void eval() { - State state = State.put(0); - assertEquals(state.run(1)._1(), state.eval(1)); + assertThat(State.gets(id()), whenEvaluated(1, 1)); } @Test public void exec() { - State state = State.put(0); - assertEquals(state.run(1)._2(), state.exec(1)); + assertThat(State.modify(x -> x + 1), whenExecuted(1, 2)); } @Test public void get() { - assertEquals(tuple(1, 1), State.get().run(1)); + assertThat(State.get(), whenRun(1, 1, 1)); } @Test public void put() { - assertEquals(tuple(UNIT, 1), State.put(1).run(1)); + assertThat(State.put(1), whenRun(1, UNIT, 1)); } @Test public void gets() { - assertEquals(tuple(0, "0"), State.gets(Integer::parseInt).run("0")); + assertThat(State.gets(Integer::parseInt), whenRun("0", 0, "0")); } @Test public void modify() { - assertEquals(tuple(UNIT, 1), State.modify(x -> x + 1).run(0)); + assertThat(State.modify(x -> x + 1), whenRun(0, UNIT, 1)); } @Test public void state() { - assertEquals(tuple(1, UNIT), State.state(1).run(UNIT)); - assertEquals(tuple(1, -1), State.state(x -> tuple(x + 1, x - 1)).run(0)); + assertThat(State.state(1), whenRun(UNIT, 1, UNIT)); + assertThat(State.state(x -> tuple(x + 1, x - 1)), whenRun(0, 1, -1)); } @Test public void stateAccumulation() { - State counter = State.get().flatMap(i -> State.put(i + 1).discardL(State.state(i))); - assertEquals(tuple(0, 1), counter.run(0)); + assertThat(State.get().flatMap(i -> State.put(i + 1).discardL(State.state(i))), + whenRun(0, 0, 1)); } @Test public void zipOrdering() { - Tuple2 result = State.state(s -> tuple(0, s + "1")) - .zip(State.>state(s -> tuple(x -> x + 1, s + "2"))) - .run("_"); - assertEquals(tuple(1, "_12"), result); + assertThat(State.state(s -> tuple(0, s + "1")) + .zip(State.state(s -> tuple(x -> x + 1, s + "2"))), + whenRun("_", 1, "_12")); } @Test public void withState() { - State modified = State.get().withState(x -> x + 1); - assertEquals(tuple(1, 1), modified.run(0)); + assertThat(State.get().withState(x -> x + 1), whenRun(0, 1, 1)); } @Test public void mapState() { - State modified = State.get().mapState(into((a, s) -> tuple(a + 1, s + 2))); - assertEquals(tuple(1, 2), modified.run(0)); + assertThat(State.get().mapState(into((a, s) -> tuple(a + 1, s + 2))), whenRun(0, 1, 2)); } @Test public void staticPure() { - State state = State.pureState().apply(1); - assertEquals(tuple(1, "foo"), state.run("foo")); + assertThat(State.pureState().apply(1), whenRun("foo", 1, "foo")); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java b/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java index fb27f6f78..c36c06a51 100644 --- a/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java @@ -1,34 +1,35 @@ package com.jnape.palatable.lambda.matchers; -import com.jnape.palatable.lambda.adt.Either; import org.junit.Test; import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.functor.builtin.State.state; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static testsupport.matchers.LeftMatcher.isLeftThat; import static testsupport.matchers.RightMatcher.isRightThat; -import static testsupport.matchers.StateMatcher.*; +import static testsupport.matchers.StateMatcher.whenEvaluatedWith; +import static testsupport.matchers.StateMatcher.whenExecutedWith; +import static testsupport.matchers.StateMatcher.whenRunWith; public class StateMatcherTest { @Test public void whenEvalWithMatcher() { - assertThat(state(Either.right(1)), - whenEvaluatedWith("0", isRightThat(equalTo(1)))); + assertThat(state(right(1)), + whenEvaluatedWith("0", isRightThat(equalTo(1)))); } @Test public void whenExecWithMatcher() { - assertThat(state(Either.right(1)), - whenExecutedWith(left("0"), isLeftThat(equalTo("0")))); + assertThat(state(right(1)), + whenExecutedWith(left("0"), isLeftThat(equalTo("0")))); } @Test public void whenRunWithMatcher() { - assertThat(state(Either.right(1)), - whenRunWith(left("0"), isRightThat(equalTo(1)), isLeftThat(equalTo("0")))); + assertThat(state(right(1)), + whenRunWith(left("0"), isRightThat(equalTo(1)), isLeftThat(equalTo("0")))); } - } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java index 39a6a22b1..e2e1b21c0 100644 --- a/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java @@ -1,9 +1,7 @@ package com.jnape.palatable.lambda.matchers; -import com.jnape.palatable.lambda.adt.Either; -import com.jnape.palatable.lambda.monad.transformer.builtin.StateT; +import org.hamcrest.core.IsEqual; import org.junit.Test; -import testsupport.matchers.StateTMatcher; import java.util.concurrent.atomic.AtomicInteger; @@ -11,6 +9,7 @@ import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.gets; import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.stateT; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; @@ -19,62 +18,64 @@ import static testsupport.matchers.IOMatcher.yieldsValue; import static testsupport.matchers.LeftMatcher.isLeftThat; import static testsupport.matchers.RightMatcher.isRightThat; -import static testsupport.matchers.StateTMatcher.*; +import static testsupport.matchers.StateTMatcher.whenEvaluatedWith; +import static testsupport.matchers.StateTMatcher.whenExecutedWith; +import static testsupport.matchers.StateTMatcher.whenRunWith; +import static testsupport.matchers.StateTMatcher.whenRunWithBoth; public class StateTMatcherTest { @Test public void whenEvaluatedWithMatcher() { assertThat(stateT(right(1)), - whenEvaluatedWith("0", isRightThat(equalTo(1)))); + whenEvaluatedWith("0", isRightThat(equalTo(1)))); } @Test public void whenEvaluatedWithMatcherOnObject() { assertThat(stateT(right(1)), - whenEvaluatedWith("0", not(equalTo(new Object())))); + whenEvaluatedWith("0", not(equalTo(new Object())))); } @Test public void whenExecutedWithMatcher() { assertThat(stateT(right(1)), - whenExecutedWith(left("0"), isRightThat(isLeftThat(equalTo("0"))))); + whenExecutedWith(left("0"), isRightThat(isLeftThat(equalTo("0"))))); } - @Test public void whenExecutedWithMatcherOnObject() { assertThat(stateT(right(1)), - whenExecutedWith(left("0"), not(equalTo(new Object())))); + whenExecutedWith(left("0"), not(equalTo(new Object())))); } @Test + @SuppressWarnings("RedundantTypeArguments") public void whenRunWithUsingTwoMatchers() { - //noinspection RedundantTypeArguments assertThat(stateT(right(1)), - StateTMatcher., Either, Integer, Either, Either>>whenRunWithBoth(left("0"), - isRightThat(equalTo(1)), - isRightThat(isLeftThat(equalTo("0"))))); + whenRunWithBoth(left("0"), + isRightThat(IsEqual.equalTo(1)), + isRightThat(isLeftThat(equalTo("0"))))); } @Test public void whenRunWithUsingOneTupleMatcher() { assertThat(stateT(right(1)), - whenRunWith(left("0"), - isRightThat(equalTo(tuple(1, left("0")))))); + whenRunWith(left("0"), + isRightThat(equalTo(tuple(1, left("0")))))); } @Test public void whenRunWithUsingOneTupleMatcherOnObject() { assertThat(stateT(right(1)), - whenRunWith(left("0"), not(equalTo(new Object())))); + whenRunWith(left("0"), not(equalTo(new Object())))); } @Test public void onlyRunsStateOnceWithTupleMatcher() { AtomicInteger count = new AtomicInteger(0); - assertThat(StateT.gets(s -> io(count::incrementAndGet)), whenRunWith(0, yieldsValue(equalTo(tuple(1, 0))))); + assertThat(gets(s -> io(count::incrementAndGet)), whenRunWith(0, yieldsValue(equalTo(tuple(1, 0))))); assertEquals(1, count.get()); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java index 967947052..b51888c9d 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java @@ -1,13 +1,18 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; -import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.adt.hlist.Tuple2; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.traits.*; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; +import testsupport.traits.MonadReaderLaws; +import testsupport.traits.MonadRecLaws; +import testsupport.traits.MonadWriterLaws; import java.util.ArrayList; import java.util.List; @@ -20,18 +25,20 @@ import static com.jnape.palatable.lambda.optics.lenses.ListLens.elementAt; import static java.util.Arrays.asList; import static org.hamcrest.MatcherAssert.assertThat; -import static testsupport.matchers.StateTMatcher.*; +import static testsupport.matchers.StateTMatcher.whenEvaluated; +import static testsupport.matchers.StateTMatcher.whenExecuted; +import static testsupport.matchers.StateTMatcher.whenRun; import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) public class StateTTest { @TestTraits({FunctorLaws.class, - ApplicativeLaws.class, - MonadLaws.class, - MonadRecLaws.class, - MonadReaderLaws.class, - MonadWriterLaws.class}) + ApplicativeLaws.class, + MonadLaws.class, + MonadRecLaws.class, + MonadReaderLaws.class, + MonadWriterLaws.class}) public Equivalence, Integer>> testReader() { return equivalence(StateT.gets(s -> new Identity<>(s.length())), s -> s.runStateT("foo")); } @@ -47,74 +54,69 @@ public void evalAndExec() { @Test public void mapStateT() { - StateT, Integer> stateT = - StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_"))); - - assertThat(stateT.mapStateT(id -> id.>>coerce() - .runIdentity() - .into((x, str) -> just(tuple(x + 1, str.toUpperCase())))), - whenRun("abc", just(tuple(4, "ABC_")))); + assertThat(StateT., Integer>stateT(str -> new Identity<>(tuple(str.length(), str + "_"))) + .mapStateT(id -> id.>>coerce() + .runIdentity() + .into((x, str) -> just(tuple(x + 1, str.toUpperCase())))), + whenRun("abc", just(tuple(4, "ABC_")))); } @Test public void zipping() { - StateT, Identity, Unit> result = StateT., Identity>modify( - s -> new Identity<>(set(elementAt(s.size()), just("one"), s))) - .discardL(StateT.modify(s -> new Identity<>(set(elementAt(s.size()), just("two"), s)))); - - assertThat(result, - whenRun(new ArrayList<>(), new Identity<>(tuple(UNIT, asList("one", "two"))))); + assertThat( + StateT., Identity>modify(s -> new Identity<>(set(elementAt(s.size()), just("one"), s))) + .discardL(StateT.modify(s -> new Identity<>(set(elementAt(s.size()), just("two"), s)))), + whenRun(new ArrayList<>(), new Identity<>(tuple(UNIT, asList("one", "two"))))); } @Test public void withStateT() { - StateT, Integer> stateT = - StateT.stateT(str -> new Identity<>(tuple(str.length(), str + "_"))); - assertThat(stateT.withStateT(str -> new Identity<>(str.toUpperCase())), - whenRun("abc", new Identity<>(tuple(3, "ABC_")))); + assertThat(StateT., Integer>stateT(str -> new Identity<>(tuple(str.length(), str + "_"))) + .withStateT(str -> new Identity<>(str.toUpperCase())), + whenRun("abc", new Identity<>(tuple(3, "ABC_")))); } @Test public void get() { assertThat(StateT.get(pureIdentity()), - whenRun("state", new Identity<>(tuple("state", "state")))); + whenRun("state", new Identity<>(tuple("state", "state")))); } @Test public void gets() { assertThat(StateT.gets(s -> new Identity<>(s.length())), - whenRun("state", new Identity<>(tuple(5, "state")))); + whenRun("state", new Identity<>(tuple(5, "state")))); } @Test public void put() { assertThat(StateT.put(new Identity<>(1)), - whenRun(0, new Identity<>(tuple(UNIT, 1)))); + whenRun(0, new Identity<>(tuple(UNIT, 1)))); } @Test public void modify() { assertThat(StateT.modify(x -> new Identity<>(x + 1)), - whenRun(0, new Identity<>(tuple(UNIT, 1)))); + whenRun(0, new Identity<>(tuple(UNIT, 1)))); } @Test public void stateT() { assertThat(StateT.stateT(new Identity<>(0)), - whenRun("_", new Identity<>(tuple(0, "_")))); + whenRun("_", new Identity<>(tuple(0, "_")))); assertThat(StateT.stateT(s -> new Identity<>(tuple(s.length(), s + "1"))), - whenRun("_", new Identity<>(tuple(1, "_1")))); + whenRun("_", new Identity<>(tuple(1, "_1")))); } @Test public void staticPure() { assertThat(StateT.>pureStateT(pureIdentity()).apply(1), - whenRun("foo", new Identity<>(tuple(1, "foo")))); + whenRun("foo", new Identity<>(tuple(1, "foo")))); } @Test public void staticLift() { assertThat(StateT.liftStateT().apply(new Identity<>(1)), - whenRun("foo", new Identity<>(tuple(1, "foo")))); + whenRun("foo", new Identity<>(tuple(1, "foo")))); } } \ No newline at end of file diff --git a/src/test/java/testsupport/matchers/StateMatcher.java b/src/test/java/testsupport/matchers/StateMatcher.java index 4f23594f3..339deada8 100644 --- a/src/test/java/testsupport/matchers/StateMatcher.java +++ b/src/test/java/testsupport/matchers/StateMatcher.java @@ -7,12 +7,14 @@ import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; -import static com.jnape.palatable.lambda.adt.These.*; +import static com.jnape.palatable.lambda.adt.These.a; +import static com.jnape.palatable.lambda.adt.These.b; +import static com.jnape.palatable.lambda.adt.These.both; import static com.jnape.palatable.lambda.io.IO.io; import static org.hamcrest.Matchers.equalTo; -public class StateMatcher extends TypeSafeMatcher> { - private final S initialState; +public final class StateMatcher extends TypeSafeMatcher> { + private final S initialState; private final These, Matcher> matchers; private StateMatcher(S initialState, These, Matcher> matchers) { @@ -24,20 +26,20 @@ private StateMatcher(S initialState, These, Matcher item) { Tuple2 ran = item.run(initialState); return matchers.match(a -> a.matches(ran._1()), - b -> b.matches(ran._2()), - ab -> ab._1().matches(ran._1()) && ab._2().matches(ran._2())); + b -> b.matches(ran._2()), + ab -> ab._1().matches(ran._1()) && ab._2().matches(ran._2())); } @Override public void describeTo(Description description) { matchers.match(a -> io(() -> a.describeTo(description.appendText("Value matching "))), - b -> io(() -> b.describeTo(description.appendText("State matching "))), - ab -> io(() -> { - description.appendText("Value matching: "); - ab._1().describeTo(description); - description.appendText(" and state matching: "); - ab._2().describeTo(description); - })) + b -> io(() -> b.describeTo(description.appendText("State matching "))), + ab -> io(() -> { + description.appendText("Value matching: "); + ab._1().describeTo(description); + description.appendText(" and state matching: "); + ab._2().describeTo(description); + })) .unsafePerformIO(); } @@ -45,27 +47,27 @@ public void describeTo(Description description) { protected void describeMismatchSafely(State item, Description mismatchDescription) { Tuple2 ran = item.run(initialState); matchers.match(a -> io(() -> { - mismatchDescription.appendText("value matching "); - a.describeMismatch(ran._1(), mismatchDescription); - }), - b -> io(() -> { - mismatchDescription.appendText("state matching "); - b.describeMismatch(ran._2(), mismatchDescription); - }), - ab -> io(() -> { - mismatchDescription.appendText("value matching: "); - ab._1().describeMismatch(ran._1(), mismatchDescription); - mismatchDescription.appendText(" and state matching: "); - ab._2().describeMismatch(ran._2(), mismatchDescription); - })) + mismatchDescription.appendText("value matching "); + a.describeMismatch(ran._1(), mismatchDescription); + }), + b -> io(() -> { + mismatchDescription.appendText("state matching "); + b.describeMismatch(ran._2(), mismatchDescription); + }), + ab -> io(() -> { + mismatchDescription.appendText("value matching: "); + ab._1().describeMismatch(ran._1(), mismatchDescription); + mismatchDescription.appendText(" and state matching: "); + ab._2().describeMismatch(ran._2(), mismatchDescription); + })) .unsafePerformIO(); } - public static StateMatcher whenRunWith(S initialState, Matcher valueMatcher, Matcher stateMatcher) { + public static StateMatcher whenRunWith(S initialState, Matcher valueMatcher, + Matcher stateMatcher) { return new StateMatcher<>(initialState, both(valueMatcher, stateMatcher)); } - @SuppressWarnings("unused") public static StateMatcher whenRun(S initialState, A value, S state) { return whenRunWith(initialState, equalTo(value), equalTo(state)); } @@ -74,7 +76,6 @@ public static StateMatcher whenExecutedWith(S initialState, Matcher return new StateMatcher<>(initialState, b(stateMatcher)); } - @SuppressWarnings("unused") public static StateMatcher whenExecuted(S initialState, S state) { return whenExecutedWith(initialState, equalTo(state)); } @@ -83,7 +84,6 @@ public static StateMatcher whenEvaluatedWith(S initialState, Matche return new StateMatcher<>(initialState, a(valueMatcher)); } - @SuppressWarnings("unused") public static StateMatcher whenEvaluated(S initialState, A value) { return whenEvaluatedWith(initialState, equalTo(value)); } diff --git a/src/test/java/testsupport/matchers/StateTMatcher.java b/src/test/java/testsupport/matchers/StateTMatcher.java index 39ec23899..8bfa97684 100644 --- a/src/test/java/testsupport/matchers/StateTMatcher.java +++ b/src/test/java/testsupport/matchers/StateTMatcher.java @@ -11,44 +11,49 @@ import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.These.a; +import static com.jnape.palatable.lambda.adt.These.b; +import static com.jnape.palatable.lambda.adt.These.both; import static com.jnape.palatable.lambda.io.IO.io; import static org.hamcrest.Matchers.equalTo; -public class StateTMatcher, A> extends TypeSafeMatcher> { +public final class StateTMatcher, A> extends TypeSafeMatcher> { private final S initialState; - private final Either, M>>, These>, Matcher>>> matcher; + private final Either< + Matcher, M>>, + These>, Matcher>>> matcher; - private StateTMatcher(S initialState, These>, Matcher>> matchers) { + private StateTMatcher(S initialState, + Either, M>>, + These>, Matcher>>> matcher) { this.initialState = initialState; - this.matcher = right(matchers); - } - - private StateTMatcher(S initialState, Matcher, M>> matcher) { - this.initialState = initialState; - this.matcher = left(matcher); + this.matcher = matcher; } @Override protected boolean matchesSafely(StateT item) { MonadRec, M> ran = item.runStateT(initialState); return matcher.match(bothMatcher -> bothMatcher.matches(ran), - theseMatchers -> theseMatchers.match(a -> a.matches(ran.fmap(Tuple2::_1)), - b -> b.matches(ran.fmap(Tuple2::_2)), - ab -> ab._1().matches(ran.fmap(Tuple2::_1)) && ab._2().matches(ran.fmap(Tuple2::_2)))); + theseMatchers -> theseMatchers.match( + a -> a.matches(ran.fmap(Tuple2::_1)), + b -> b.matches(ran.fmap(Tuple2::_2)), + ab -> ab._1().matches(ran.fmap(Tuple2::_1)) + && ab._2().matches(ran.fmap(Tuple2::_2)))); } @Override public void describeTo(Description description) { - matcher.match(bothMatcher -> io(() -> bothMatcher.describeTo(description.appendText("Value and state matching "))), - theseMatchers -> theseMatchers.match(a -> io(() -> a.describeTo(description.appendText("Value matching "))), - b -> io(() -> b.describeTo(description.appendText("State matching "))), - ab -> io(() -> { - description.appendText("Value run matching: "); - ab._1().describeTo(description); - description.appendText(", then state run matching: "); - ab._2().describeTo(description); - }))) + matcher.match(both -> io(() -> both.describeTo(description.appendText("Value and state matching "))), + these -> these.match( + a -> io(() -> a.describeTo(description.appendText("Value matching "))), + b -> io(() -> b.describeTo(description.appendText("State matching "))), + ab -> io(() -> { + description.appendText("Value run matching: "); + ab._1().describeTo(description); + description.appendText(", then state run matching: "); + ab._2().describeTo(description); + }))) .unsafePerformIO(); } @@ -57,62 +62,73 @@ protected void describeMismatchSafely(StateT item, Description mismatch MonadRec, M> ran = item.runStateT(initialState); matcher.match(bothMatcher -> io(() -> { - mismatchDescription.appendText("value and state matching "); - bothMatcher.describeMismatch(ran, mismatchDescription); - }), - theseMatchers -> theseMatchers.match(a -> io(() -> { - mismatchDescription.appendText("value matching "); - a.describeMismatch(ran.fmap(Tuple2::_1), mismatchDescription); - }), - b -> io(() -> { - mismatchDescription.appendText("state matching "); - b.describeMismatch(ran.fmap(Tuple2::_2), mismatchDescription); - }), - ab -> io(() -> { - mismatchDescription.appendText("value run matching: "); - ab._1().describeMismatch(ran.fmap(Tuple2::_1), mismatchDescription); - mismatchDescription.appendText(", then state run matching: "); - ab._2().describeMismatch(ran.fmap(Tuple2::_2), mismatchDescription); - }))) + mismatchDescription.appendText("value and state matching "); + bothMatcher.describeMismatch(ran, mismatchDescription); + }), + theseMatchers -> theseMatchers.match( + a -> io(() -> { + mismatchDescription.appendText("value matching "); + a.describeMismatch(ran.fmap(Tuple2::_1), mismatchDescription); + }), + b -> io(() -> { + mismatchDescription.appendText("state matching "); + b.describeMismatch(ran.fmap(Tuple2::_2), mismatchDescription); + }), + ab -> io(() -> { + mismatchDescription.appendText("value run matching: "); + ab._1().describeMismatch(ran.fmap(Tuple2::_1), mismatchDescription); + mismatchDescription.appendText(", then state run matching: "); + ab._2().describeMismatch(ran.fmap(Tuple2::_2), mismatchDescription); + }))) .unsafePerformIO(); } - public static , A, MAS extends MonadRec, M>> StateTMatcher whenRunWith(S initialState, Matcher bothMatcher) { - return new StateTMatcher(initialState, extendMatcher(bothMatcher)); + public static , A, MAS extends MonadRec, M>> StateTMatcher + whenRunWith(S initialState, Matcher bothMatcher) { + return new StateTMatcher(initialState, left(extendMatcher(bothMatcher))); } - public static , A> StateTMatcher whenRun(S initialState, MonadRec, M> both) { + public static , A> StateTMatcher whenRun( + S initialState, MonadRec, M> both) { return whenRunWith(initialState, equalTo(both)); } - // Note: This constructor will run both matchers, which will run effects twice - public static , A, MA extends MonadRec, MS extends MonadRec> StateTMatcher whenRunWithBoth(S initialState, Matcher valueMatcher, Matcher stateMatcher) { - return new StateTMatcher(initialState, These.both(extendMatcher(valueMatcher), extendMatcher(stateMatcher))); + public static , A, MA extends MonadRec, MS extends MonadRec> + StateTMatcher whenRunWithBoth(S initialState, + Matcher valueMatcher, + Matcher stateMatcher) { + return new StateTMatcher(initialState, right(both(extendMatcher(valueMatcher), + extendMatcher(stateMatcher)))); } - // Note: This constructor will run both matchers, which will run effects twice - @SuppressWarnings("unused") - public static , A, MA extends MonadRec, MS extends MonadRec> StateTMatcher whenRunBoth(S initialState, MonadRec value, MonadRec state) { + public static , A> StateTMatcher whenRunBoth(S initialState, + MonadRec value, + MonadRec state) { return whenRunWithBoth(initialState, equalTo(value), equalTo(state)); } - public static , A, MS extends MonadRec> StateTMatcher whenExecutedWith(S initialState, Matcher stateMatcher) { - return new StateTMatcher(initialState, These.b(extendMatcher(stateMatcher))); + public static , A, MS extends MonadRec> StateTMatcher whenExecutedWith( + S initialState, Matcher stateMatcher) { + return new StateTMatcher(initialState, right(b(extendMatcher(stateMatcher)))); } - public static , A> StateTMatcher whenExecuted(S initialState, MonadRec state) { + public static , A> StateTMatcher whenExecuted(S initialState, + MonadRec state) { return whenExecutedWith(initialState, equalTo(state)); } - public static , A, MA extends MonadRec> StateTMatcher whenEvaluatedWith(S initialState, Matcher valueMatcher) { - return new StateTMatcher(initialState, These.a(extendMatcher(valueMatcher))); + public static , A, MA extends MonadRec> StateTMatcher whenEvaluatedWith( + S initialState, Matcher valueMatcher) { + return new StateTMatcher(initialState, right(a(extendMatcher(valueMatcher)))); } - public static , A> StateTMatcher whenEvaluated(S initialState, MonadRec value) { + public static , A> StateTMatcher whenEvaluated(S initialState, + MonadRec value) { return whenEvaluatedWith(initialState, equalTo(value)); } - private static , MX extends MonadRec> Matcher> extendMatcher(Matcher matcher) { + private static , MX extends MonadRec> Matcher> extendMatcher( + Matcher matcher) { return new TypeSafeMatcher>() { @Override protected boolean matchesSafely(MonadRec item) { From 50448da248f596b9f822be6fcd4b900bca76427d Mon Sep 17 00:00:00 2001 From: "jon.woolwine" Date: Thu, 12 Dec 2019 11:09:46 -0600 Subject: [PATCH 290/348] Adding MaybeT::filter --- .../lambda/monad/transformer/builtin/MaybeT.java | 11 +++++++++++ .../lambda/monad/transformer/builtin/MaybeTTest.java | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index ca588a7bc..da2ce2725 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -44,6 +44,17 @@ public , M>> MMA runMaybeT() { return mma.coerce(); } + /** + * If the embedded value is present and satisfies predicate + * then return just the embedded value + * + * @param predicate the predicate to apply to the embedded value + * @return maybe the satisfied value embedded under M + */ + public MaybeT filter(Fn1 predicate) { + return maybeT(mma.fmap(ma -> ma.filter(predicate))); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java index 6af53f359..87e0f9df5 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java @@ -22,6 +22,8 @@ import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn2.GT.gt; +import static com.jnape.palatable.lambda.functions.builtin.fn2.LT.lt; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.io.IO.io; @@ -70,4 +72,11 @@ public void composedZip() { .unsafePerformAsyncIO(Executors.newFixedThreadPool(2)) .join(); } + + @Test + public void filter() { + MaybeT, Integer> maybeT = pureMaybeT(pureIdentity()).apply(1); + assertEquals(maybeT(new Identity<>(just(1))), maybeT.filter(gt(0))); + assertEquals(maybeT(new Identity<>(nothing())), maybeT.filter(lt(0))); + } } \ No newline at end of file From 44324d4d2d6e0be180242179234a02589f2d6302 Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Fri, 20 Dec 2019 11:42:16 -0600 Subject: [PATCH 291/348] Added EitherMatcher in place of Left/RightMatcher --- .../jnape/palatable/lambda/adt/TryTest.java | 2 +- .../functions/builtin/fn1/CoalesceTest.java | 4 +- .../lambda/matchers/StateMatcherTest.java | 4 +- .../lambda/matchers/StateTMatcherTest.java | 4 +- .../testsupport/matchers/EitherMatcher.java | 54 +++++++++++++++++++ .../testsupport/matchers/LeftMatcher.java | 44 --------------- .../testsupport/matchers/RightMatcher.java | 44 --------------- 7 files changed, 61 insertions(+), 95 deletions(-) create mode 100644 src/test/java/testsupport/matchers/EitherMatcher.java delete mode 100644 src/test/java/testsupport/matchers/LeftMatcher.java delete mode 100644 src/test/java/testsupport/matchers/RightMatcher.java diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java index 1d4ed3b0f..dd4ff5dfb 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TryTest.java @@ -41,7 +41,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static testsupport.assertion.MonadErrorAssert.assertLaws; -import static testsupport.matchers.LeftMatcher.isLeftThat; +import static testsupport.matchers.EitherMatcher.isLeftThat; @RunWith(Traits.class) public class TryTest { diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CoalesceTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CoalesceTest.java index 68db636c1..6502e6104 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CoalesceTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CoalesceTest.java @@ -8,10 +8,10 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static org.junit.Assert.assertThat; +import static testsupport.matchers.EitherMatcher.isLeftThat; +import static testsupport.matchers.EitherMatcher.isRightThat; import static testsupport.matchers.IterableMatcher.isEmpty; import static testsupport.matchers.IterableMatcher.iterates; -import static testsupport.matchers.LeftMatcher.isLeftThat; -import static testsupport.matchers.RightMatcher.isRightThat; public class CoalesceTest { diff --git a/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java b/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java index c36c06a51..42e1eddd3 100644 --- a/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/matchers/StateMatcherTest.java @@ -7,8 +7,8 @@ import static com.jnape.palatable.lambda.functor.builtin.State.state; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; -import static testsupport.matchers.LeftMatcher.isLeftThat; -import static testsupport.matchers.RightMatcher.isRightThat; +import static testsupport.matchers.EitherMatcher.isLeftThat; +import static testsupport.matchers.EitherMatcher.isRightThat; import static testsupport.matchers.StateMatcher.whenEvaluatedWith; import static testsupport.matchers.StateMatcher.whenExecutedWith; import static testsupport.matchers.StateMatcher.whenRunWith; diff --git a/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java index e2e1b21c0..562bb8bb4 100644 --- a/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java +++ b/src/test/java/com/jnape/palatable/lambda/matchers/StateTMatcherTest.java @@ -15,9 +15,9 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static org.junit.Assert.assertEquals; +import static testsupport.matchers.EitherMatcher.isLeftThat; +import static testsupport.matchers.EitherMatcher.isRightThat; import static testsupport.matchers.IOMatcher.yieldsValue; -import static testsupport.matchers.LeftMatcher.isLeftThat; -import static testsupport.matchers.RightMatcher.isRightThat; import static testsupport.matchers.StateTMatcher.whenEvaluatedWith; import static testsupport.matchers.StateTMatcher.whenExecutedWith; import static testsupport.matchers.StateTMatcher.whenRunWith; diff --git a/src/test/java/testsupport/matchers/EitherMatcher.java b/src/test/java/testsupport/matchers/EitherMatcher.java new file mode 100644 index 000000000..748d01be2 --- /dev/null +++ b/src/test/java/testsupport/matchers/EitherMatcher.java @@ -0,0 +1,54 @@ +package testsupport.matchers; + +import com.jnape.palatable.lambda.adt.Either; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.io.IO.io; + +public final class EitherMatcher extends TypeSafeMatcher> { + private final Either, Matcher> matcher; + + private EitherMatcher(Either, Matcher> matcher) { + this.matcher = matcher; + } + + @Override + protected void describeMismatchSafely(Either item, Description mismatchDescription) { + mismatchDescription.appendText("was "); + item.match(l -> matcher.match(lMatcher -> io(() -> lMatcher.describeMismatch(l, mismatchDescription)), + rMatcher -> io(() -> mismatchDescription.appendValue(item))), + r -> matcher.match(lMatcher -> io(() -> mismatchDescription.appendValue(item)), + lMatcher -> io(() -> lMatcher.describeMismatch(r, mismatchDescription)))) + .unsafePerformIO(); + } + + @Override + protected boolean matchesSafely(Either actual) { + return actual.match(l -> matcher.match(lMatcher -> lMatcher.matches(l), + constantly(false)), + r -> matcher.match(constantly(false), + rMatcher -> rMatcher.matches(r))); + } + + @Override + public void describeTo(Description description) { + matcher.match(l -> io(() -> description.appendText("Left value of ")) + .flatMap(constantly(io(() -> l.describeTo(description)))), + r -> io(() -> description.appendText("Right value of ")) + .flatMap(constantly(io(() -> r.describeTo(description))))) + .unsafePerformIO(); + } + + public static EitherMatcher isLeftThat(Matcher lMatcher) { + return new EitherMatcher<>(left(lMatcher)); + } + + public static EitherMatcher isRightThat(Matcher rMatcher) { + return new EitherMatcher<>(right(rMatcher)); + } +} diff --git a/src/test/java/testsupport/matchers/LeftMatcher.java b/src/test/java/testsupport/matchers/LeftMatcher.java deleted file mode 100644 index 34ea33079..000000000 --- a/src/test/java/testsupport/matchers/LeftMatcher.java +++ /dev/null @@ -1,44 +0,0 @@ -package testsupport.matchers; - -import com.jnape.palatable.lambda.adt.Either; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.io.IO.io; - -public final class LeftMatcher extends TypeSafeMatcher> { - - private final Matcher lMatcher; - - private LeftMatcher(Matcher lMatcher) { - this.lMatcher = lMatcher; - } - - @Override - protected boolean matchesSafely(Either actual) { - return actual.match(lMatcher::matches, constantly(false)); - } - - @Override - public void describeTo(Description description) { - description.appendText("Left value of "); - lMatcher.describeTo(description); - } - - @Override - protected void describeMismatchSafely(Either item, Description mismatchDescription) { - mismatchDescription.appendText("was "); - item.match(l -> io(() -> { - mismatchDescription.appendText("Left value of "); - lMatcher.describeMismatch(l, mismatchDescription); - }), - r -> io(() -> mismatchDescription.appendValue(item))) - .unsafePerformIO(); - } - - public static LeftMatcher isLeftThat(Matcher lMatcher) { - return new LeftMatcher<>(lMatcher); - } -} diff --git a/src/test/java/testsupport/matchers/RightMatcher.java b/src/test/java/testsupport/matchers/RightMatcher.java deleted file mode 100644 index 1eafc0ab1..000000000 --- a/src/test/java/testsupport/matchers/RightMatcher.java +++ /dev/null @@ -1,44 +0,0 @@ -package testsupport.matchers; - -import com.jnape.palatable.lambda.adt.Either; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; - -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -import static com.jnape.palatable.lambda.io.IO.io; - -public final class RightMatcher extends TypeSafeMatcher> { - - private final Matcher rMatcher; - - private RightMatcher(Matcher rMatcher) { - this.rMatcher = rMatcher; - } - - @Override - protected boolean matchesSafely(Either actual) { - return actual.match(constantly(false), rMatcher::matches); - } - - @Override - public void describeTo(Description description) { - description.appendText("Right value of "); - rMatcher.describeTo(description); - } - - @Override - protected void describeMismatchSafely(Either item, Description mismatchDescription) { - mismatchDescription.appendText("was "); - item.match(l -> io(() -> mismatchDescription.appendValue(item)), - r -> io(() -> { - mismatchDescription.appendText("Right value of "); - rMatcher.describeMismatch(r, mismatchDescription); - })) - .unsafePerformIO(); - } - - public static RightMatcher isRightThat(Matcher rMatcher) { - return new RightMatcher<>(rMatcher); - } -} From 269cbbcfd3b5594ad18a15b2a12be89f2c9d1d1c Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 7 Jan 2020 10:27:11 -0600 Subject: [PATCH 292/348] Adding identity function overload --- .../com/jnape/palatable/lambda/functions/builtin/fn1/Id.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java index c2f8c06ee..c92cf0c81 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn1/Id.java @@ -23,4 +23,8 @@ public A checkedApply(A a) { public static Id id() { return (Id) INSTANCE; } + + public static A id(A a) { + return Id.id().apply(a); + } } From 75b1fb70fe1720966131beb357d5a4836d8493f7 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 7 Jan 2020 10:54:15 -0600 Subject: [PATCH 293/348] Adding MaybeT#or for choosing the first present effect result --- CHANGELOG.md | 3 +++ .../lambda/monad/transformer/builtin/MaybeT.java | 14 +++++++++++++- .../monad/transformer/builtin/MaybeTTest.java | 16 +++++++++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1afe4208b..db04728bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `MergeHMaps`, a `Monoid` that merges `HMap`s by merging the values via key-specified `Semigroup`s +- `Id#id` overload that accepts an argument and returns it +- `MaybeT#or`, choose the first `MaybeT` that represents an effect around `just` a value +- `StateMatcher, StateTMatcher, WriterTMatcher` ## [5.1.0] - 2019-10-13 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index da2ce2725..c2e02fd94 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -55,6 +55,18 @@ public MaybeT filter(Fn1 predicate) { return maybeT(mma.fmap(ma -> ma.filter(predicate))); } + /** + * Returns the first {@link MaybeT} that is an effect around {@link Maybe#just(Object) just} a result. + * + * @param other the other {@link MaybeT} + * @return the first present {@link MaybeT} + */ + public MaybeT or(MaybeT other) { + MonadRec, M> mMaybeA = runMaybeT(); + return maybeT(mMaybeA.flatMap(maybeA -> maybeA.match(constantly(other.runMaybeT()), + a -> mMaybeA.pure(just(a))))); + } + /** * {@inheritDoc} */ @@ -145,7 +157,7 @@ public MaybeT discardR(Applicative> appB) { @Override public boolean equals(Object other) { - return other instanceof MaybeT && Objects.equals(mma, ((MaybeT) other).mma); + return other instanceof MaybeT && Objects.equals(mma, ((MaybeT) other).mma); } @Override diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java index 87e0f9df5..2c578fbc6 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java @@ -27,9 +27,7 @@ import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.io.IO.io; -import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.liftMaybeT; -import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.maybeT; -import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.pureMaybeT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.*; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -79,4 +77,16 @@ public void filter() { assertEquals(maybeT(new Identity<>(just(1))), maybeT.filter(gt(0))); assertEquals(maybeT(new Identity<>(nothing())), maybeT.filter(lt(0))); } + + @Test + public void orSelectsFirstPresentValueInsideEffect() { + assertEquals(maybeT(new Identity<>(just(1))), + maybeT(new Identity<>(just(1))).or(maybeT(new Identity<>(nothing())))); + + assertEquals(maybeT(new Identity<>(just(1))), + maybeT(new Identity<>(nothing())).or(maybeT(new Identity<>(just(1))))); + + assertEquals(maybeT(new Identity<>(just(1))), + maybeT(new Identity<>(just(1))).or(maybeT(new Identity<>(just(2))))); + } } \ No newline at end of file From d81d23563f5bb5c1b86094b33eaf3743d4ae6dee Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 7 Jan 2020 11:04:49 -0600 Subject: [PATCH 294/348] Adding ReaderT#and, category composition between ReaderTs --- CHANGELOG.md | 1 + .../monad/transformer/builtin/ReaderT.java | 12 ++++++++++++ .../monad/transformer/builtin/ReaderTTest.java | 16 ++++++++++------ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db04728bb..0ae3bdcf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Id#id` overload that accepts an argument and returns it - `MaybeT#or`, choose the first `MaybeT` that represents an effect around `just` a value - `StateMatcher, StateTMatcher, WriterTMatcher` +- `ReaderT#and`, category composition between `ReaderT` instances: `(a -> m b) -> (b -> m c) -> (a -> m c)` ## [5.1.0] - 2019-10-13 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index 2af18e16d..443470c6e 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -61,6 +61,18 @@ public , N extends MonadRec, B> ReaderT return readerT(r -> fn.apply(runReaderT(r).coerce())); } + /** + * Left-to-right composition between {@link ReaderT} instances running under the same effect and compatible between + * their inputs and outputs. + * + * @param amb the next {@link ReaderT} to run + * @param the final output type + * @return the composed {@link ReaderT} + */ + public ReaderT and(ReaderT amb) { + return readerT(r -> runReaderT(r).flatMap(amb::runReaderT)); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java index 3ea0710ff..6972c9fb6 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java @@ -8,12 +8,7 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.traits.ApplicativeLaws; -import testsupport.traits.Equivalence; -import testsupport.traits.FunctorLaws; -import testsupport.traits.MonadLaws; -import testsupport.traits.MonadReaderLaws; -import testsupport.traits.MonadRecLaws; +import testsupport.traits.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; @@ -58,6 +53,15 @@ public void mapReaderT() { .runReaderT("foo")); } + @Test + public void andComposesLeftToRight() { + ReaderT, Float> intToFloat = readerT(x -> new Identity<>(x.floatValue())); + ReaderT, Double> floatToDouble = readerT(f -> new Identity<>(f.doubleValue())); + + assertEquals(new Identity<>(1.), + intToFloat.and(floatToDouble).runReaderT(1)); + } + @Test public void staticPure() { ReaderT, Integer> readerT = From 39f79d2825da3ad4db4508b96d4e92275b597bc5 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 28 Jan 2020 17:36:45 -0600 Subject: [PATCH 295/348] IterateT, ListT done right (https://wiki.haskell.org/ListT_done_right) --- CHANGELOG.md | 1 + .../{iteration => }/ImmutableQueue.java | 43 +- .../{iteration => }/ImmutableStack.java | 23 +- .../iteration/ConcatenatingIterable.java | 2 + .../iteration/TrampoliningIterator.java | 1 + .../monad/transformer/builtin/IterateT.java | 435 ++++++++++++++++++ .../transformer/builtin/IterateTTest.java | 230 +++++++++ .../testsupport/matchers/IterableMatcher.java | 16 +- .../testsupport/matchers/IterateTMatcher.java | 48 ++ 9 files changed, 765 insertions(+), 34 deletions(-) rename src/main/java/com/jnape/palatable/lambda/internal/{iteration => }/ImmutableQueue.java (70%) rename src/main/java/com/jnape/palatable/lambda/internal/{iteration => }/ImmutableStack.java (77%) create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java create mode 100644 src/test/java/testsupport/matchers/IterateTMatcher.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ae3bdcf8..f53bb7d6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `MaybeT#or`, choose the first `MaybeT` that represents an effect around `just` a value - `StateMatcher, StateTMatcher, WriterTMatcher` - `ReaderT#and`, category composition between `ReaderT` instances: `(a -> m b) -> (b -> m c) -> (a -> m c)` +- `IterateT`, [`ListT` done right](https://wiki.haskell.org/ListT_done_right) ## [5.1.0] - 2019-10-13 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableQueue.java b/src/main/java/com/jnape/palatable/lambda/internal/ImmutableQueue.java similarity index 70% rename from src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableQueue.java rename to src/main/java/com/jnape/palatable/lambda/internal/ImmutableQueue.java index 1b683c870..dd605015e 100644 --- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableQueue.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/ImmutableQueue.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.internal.iteration; +package com.jnape.palatable.lambda.internal; import com.jnape.palatable.lambda.adt.Maybe; @@ -8,22 +8,29 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; -abstract class ImmutableQueue implements Iterable { +/** + * Internal API. Use at your own peril. + */ +public abstract class ImmutableQueue implements Iterable { - abstract ImmutableQueue pushFront(A a); + public abstract ImmutableQueue pushFront(A a); - abstract ImmutableQueue pushBack(A a); + public abstract ImmutableQueue pushBack(A a); - abstract Maybe head(); + public abstract Maybe head(); - abstract ImmutableQueue tail(); + public abstract ImmutableQueue tail(); - abstract ImmutableQueue concat(ImmutableQueue other); + public abstract ImmutableQueue concat(ImmutableQueue other); - final boolean isEmpty() { + public final boolean isEmpty() { return head().fmap(constantly(false)).orElse(true); } + public static ImmutableQueue singleton(A a) { + return new NonEmpty<>(ImmutableStack.empty().push(a), ImmutableStack.empty()); + } + @Override public Iterator iterator() { return new Iterator() { @@ -52,27 +59,27 @@ private static final class Empty extends ImmutableQueue { private static final Empty INSTANCE = new Empty<>(); @Override - ImmutableQueue pushFront(A a) { + public ImmutableQueue pushFront(A a) { return new NonEmpty<>(ImmutableStack.empty().push(a), ImmutableStack.empty()); } @Override - ImmutableQueue pushBack(A a) { + public ImmutableQueue pushBack(A a) { return pushFront(a); } @Override - ImmutableQueue concat(ImmutableQueue other) { + public ImmutableQueue concat(ImmutableQueue other) { return other; } @Override - Maybe head() { + public Maybe head() { return Maybe.nothing(); } @Override - ImmutableQueue tail() { + public ImmutableQueue tail() { return this; } } @@ -87,27 +94,27 @@ private NonEmpty(ImmutableStack outbound, ImmutableStack inbound) { } @Override - ImmutableQueue pushFront(A a) { + public ImmutableQueue pushFront(A a) { return new NonEmpty<>(outbound.push(a), inbound); } @Override - ImmutableQueue pushBack(A a) { + public ImmutableQueue pushBack(A a) { return new NonEmpty<>(outbound, inbound.push(a)); } @Override - ImmutableQueue concat(ImmutableQueue other) { + public ImmutableQueue concat(ImmutableQueue other) { return new NonEmpty<>(outbound, foldLeft(ImmutableStack::push, inbound, other)); } @Override - Maybe head() { + public Maybe head() { return outbound.head(); } @Override - ImmutableQueue tail() { + public ImmutableQueue tail() { ImmutableStack outTail = outbound.tail(); if (!outTail.isEmpty()) return new NonEmpty<>(outTail, inbound); diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableStack.java b/src/main/java/com/jnape/palatable/lambda/internal/ImmutableStack.java similarity index 77% rename from src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableStack.java rename to src/main/java/com/jnape/palatable/lambda/internal/ImmutableStack.java index a337ec21b..cc6e7175b 100644 --- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/ImmutableStack.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/ImmutableStack.java @@ -1,4 +1,4 @@ -package com.jnape.palatable.lambda.internal.iteration; +package com.jnape.palatable.lambda.internal; import com.jnape.palatable.lambda.adt.Maybe; @@ -7,17 +7,20 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; -abstract class ImmutableStack implements Iterable { +/** + * Internal API. Use at your own peril. + */ +public abstract class ImmutableStack implements Iterable { - final ImmutableStack push(A a) { + public final ImmutableStack push(A a) { return new Node<>(a, this); } - abstract Maybe head(); + public abstract Maybe head(); - abstract ImmutableStack tail(); + public abstract ImmutableStack tail(); - final boolean isEmpty() { + public final boolean isEmpty() { return head().fmap(constantly(false)).orElse(true); } @@ -49,12 +52,12 @@ private static final class Empty extends ImmutableStack { private static final Empty INSTANCE = new Empty<>(); @Override - Maybe head() { + public Maybe head() { return Maybe.nothing(); } @Override - ImmutableStack tail() { + public ImmutableStack tail() { return this; } } @@ -69,12 +72,12 @@ public Node(A head, ImmutableStack tail) { } @Override - Maybe head() { + public Maybe head() { return Maybe.just(head); } @Override - ImmutableStack tail() { + public ImmutableStack tail() { return tail; } } diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java index 594be70b2..f1ff3a779 100644 --- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/ConcatenatingIterable.java @@ -1,5 +1,7 @@ package com.jnape.palatable.lambda.internal.iteration; +import com.jnape.palatable.lambda.internal.ImmutableQueue; + import java.util.Iterator; import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten; diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIterator.java index fa0350d08..3b2a7b37f 100644 --- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/TrampoliningIterator.java @@ -3,6 +3,7 @@ import com.jnape.palatable.lambda.functions.Fn0; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; +import com.jnape.palatable.lambda.internal.ImmutableQueue; import java.util.Iterator; import java.util.NoSuchElementException; diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java new file mode 100644 index 000000000..82fe5ee67 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -0,0 +1,435 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.choice.Choice2; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; +import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; +import com.jnape.palatable.lambda.functions.specialized.Pure; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.internal.ImmutableQueue; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +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.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.choice.Choice2.a; +import static com.jnape.palatable.lambda.adt.choice.Choice2.b; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; +import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; +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.io.IO.io; +import static com.jnape.palatable.lambda.monad.Monad.join; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.maybeT; +import static java.util.Arrays.asList; + +/** + * A {@link MonadT monad transformer} over a co-inductive, singly-linked spine of values embedded in effects. This is + * analogous to Haskell's ListT (done right). All append + * operations ({@link IterateT#cons(MonadRec) cons}, {@link IterateT#snoc(MonadRec) snoc}, etc.) are O(1) space/time + * complexity. + *

+ * Due to its singly-linked embedded design, {@link IterateT} is a canonical example of purely-functional streaming + * computation. For example, to lazily print all lines from a file descriptor, an initial implementation using + * {@link IterateT} might take the following form: + *


+ * String filePath = "/tmp/a_tale_of_two_cities.txt";
+ * IterateT<IO<?>, String> streamLines = IterateT.unfold(
+ *         reader -> io(() -> maybe(reader.readLine()).fmap(line -> tuple(line, reader))),
+ *         io(() -> Files.newBufferedReader(Paths.get(filePath))));
+ *
+ * // iterative read and print lines without retaining references
+ * IO<Unit> printLines = streamLines.forEach(line -> io(() -> System.out.println(line)));
+ * printLines.unsafePerformIO(); // prints "It was the best of times, it was the worst of times, [...]"
+ * 
+ * + * @param the effect type + * @param the element type + */ +public class IterateT, A> implements + MonadT, IterateT> { + + private final Pure pureM; + private final ImmutableQueue> conses; + private final ImmutableQueue>>, M>>, IterateT>> middles; + private final ImmutableQueue> snocs; + + private IterateT(Pure pureM, + ImmutableQueue> conses, + ImmutableQueue>>, M>>, IterateT>> middles, + ImmutableQueue> snocs) { + this.pureM = pureM; + this.conses = conses; + this.middles = middles; + this.snocs = snocs; + } + + /** + * Recover the full structure of the embedded {@link Monad}. + * + * @param the witnessed target type + * @return the embedded {@link Monad} + */ + public >>, M>> MMTA runIterateT() { + return pureM., MonadRec, M>>apply(this).trampolineM(IterateT::resume).coerce(); + } + + /** + * Add an element inside an effect to the front of this {@link IterateT}. + * + * @param head the element + * @return the cons'ed {@link IterateT} + */ + public final IterateT cons(MonadRec head) { + return new IterateT<>(pureM, conses.pushFront(head), middles, snocs); + } + + /** + * Add an element inside an effect to the back of this {@link IterateT}. + * + * @param last the element + * @return the snoc'ed {@link IterateT} + */ + public final IterateT snoc(MonadRec last) { + return new IterateT<>(pureM, conses, middles, snocs.pushBack(last)); + } + + /** + * Concat this {@link IterateT} in front of the other {@link IterateT}. + * + * @param other the other {@link IterateT} + * @return the concatenated {@link IterateT} + */ + public IterateT concat(IterateT other) { + return new IterateT<>(pureM, + conses, + middles.pushBack(b(new IterateT<>(pureM, + snocs.concat(other.conses), + other.middles, + other.snocs))), + ImmutableQueue.empty()); + } + + /** + * Monolithically fold the spine of this {@link IterateT} by {@link MonadRec#trampolineM(Fn1) trampolining} the + * underlying effects (for iterative folding, use {@link IterateT#trampolineM(Fn1) trampolineM} directly). + * + * @param fn the folding function + * @param acc the starting accumulation effect + * @param the accumulation type + * @param the witnessed target result type + * @return the folded effect result + */ + public > MB fold(Fn2> fn, + MonadRec acc) { + return acc.fmap(tupler(this)) + .trampolineM(into((as, b) -> maybeT(as.runIterateT()) + .flatMap(into((a, aas) -> maybeT(fn.apply(b, a).fmap(tupler(aas)).fmap(Maybe::just)))) + .runMaybeT() + .fmap(maybeRecur -> maybeRecur.match(constantly(terminate(b)), RecursiveResult::recurse)))) + .coerce(); + } + + /** + * Convenience method for {@link IterateT#fold(Fn2, MonadRec) folding} the spine of this {@link IterateT} with + * an action to perform on each element without accumulating any results. + * + * @param fn the action to perform on each element + * @param the witnessed target result type + * @return the folded effect result + */ + public > MU forEach(Fn1> fn) { + return fold((__, a) -> fn.apply(a), runIterateT().pure(UNIT)); + } + + /** + * {@inheritDoc} + */ + @Override + public > IterateT lift(MonadRec nb) { + return singleton(nb); + } + + /** + * {@inheritDoc} + */ + @Override + public IterateT trampolineM( + Fn1, IterateT>> fn) { + return trampolineM(fn, ImmutableQueue.>>empty().pushBack(flatMap(fn))); + } + + /** + * {@inheritDoc} + */ + @Override + public IterateT flatMap(Fn1>> f) { + return suspended(() -> maybeT(runIterateT()) + .flatMap(into((a, as) -> maybeT(f.apply(a) + .>coerce() + .concat(as.flatMap(f)) + .runIterateT()))) + .runMaybeT(), pureM); + } + + /** + * {@inheritDoc} + */ + @Override + public IterateT fmap(Fn1 fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public IterateT pure(B b) { + return singleton(runIterateT().pure(b)); + } + + /** + * Force the underlying spine of this {@link IterateT} into a {@link Collection} of type C inside the + * context of the monadic effect, using the provided cFn0 to construct the initial instance. + *

+ * Note that this is a fundamentally monolithic operation - meaning that incremental progress is not possible - and + * as such, calling this on an infinite {@link IterateT} will result in either heap exhaustion (e.g. in the case of + * {@link List lists}) or non-termination (e.g. in the case of {@link Set sets}). + * + * @param the {@link Collection} type + * @param the witnessed target type + * @return the {@link List} inside of the effect + */ + public , MAS extends MonadRec> MAS toCollection(Fn0 cFn0) { + MonadRec>>, M> mmta = runIterateT(); + return fold((c, a) -> { + c.add(a); + return mmta.pure(c); + }, mmta.pure(cFn0.apply())); + } + + /** + * {@inheritDoc} + */ + @Override + public IterateT zip(Applicative, IterateT> appFn) { + return suspended(() -> { + MonadRec>>, M> mmta = runIterateT(); + return join(maybeT(mmta).zip( + maybeT(appFn.>>coerce().runIterateT()) + .fmap(into((f, fs) -> into((a, as) -> maybeT( + as.fmap(f) + .cons(mmta.pure(f.apply(a))) + .concat(as.cons(mmta.pure(a)).zip(fs)) + .runIterateT())))))) + .runMaybeT(); + }, pureM); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, IterateT>> lazyAppFn) { + return lazyAppFn.fmap(this::zip); + } + + /** + * {@inheritDoc} + */ + @Override + public IterateT discardL(Applicative> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public IterateT discardR(Applicative> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + private MonadRec, Maybe>>>, M> resume() { + return conses.head().match( + __ -> middles.head().match( + ___ -> snocs.head().match( + ____ -> pureM.apply(terminate(nothing())), + ma -> ma.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, + snocs.tail(), + ImmutableQueue.empty(), + ImmutableQueue.empty())))))), + lazyOrStrict -> lazyOrStrict.match( + lazy -> lazy.apply().fmap(maybeRes -> maybeRes.match( + ___ -> recurse(new IterateT<>(pureM, ImmutableQueue.empty(), middles.tail(), snocs)), + into((a, as) -> recurse(new IterateT<>(pureM, + ImmutableQueue.singleton(pureM.apply(a)), + ImmutableQueue.singleton(b(migrateForward(as))), + ImmutableQueue.empty()))) + )), + strict -> pureM.apply(recurse(migrateForward(strict))))), + ma -> ma.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, conses.tail(), middles, snocs)))))); + } + + private IterateT migrateForward(IterateT as) { + if (middles.tail().isEmpty()) { + return new IterateT<>(pureM, conses.concat(as.conses), as.middles, as.snocs.concat(snocs)); + } + + IterateT lasts = new IterateT<>(pureM, as.snocs, middles.tail(), snocs); + return new IterateT<>(pureM, as.conses, as.middles.pushBack(b(lasts)), ImmutableQueue.empty()); + } + + private IterateT trampolineM(Fn1, IterateT>> fn, + ImmutableQueue>> queued) { + return suspended(() -> { + MonadRec>>, M> pureQueue = pureM.apply(queued); + return pureQueue.trampolineM( + q -> q.head().match( + __ -> pureM.apply(terminate(nothing())), + next -> next.runIterateT().flatMap(maybeMore -> maybeMore.match( + __ -> pureM.apply(terminate(nothing())), + t -> t.into((aOrB, rest) -> aOrB.match( + a -> pureM.apply(recurse(q.pushFront(fn.apply(a).coerce()))), + b -> trampolineM(fn, q.tail().pushFront(rest)) + .cons(pureM.apply(b)) + .runIterateT() + .fmap(RecursiveResult::terminate))))))); + }, pureM); + } + + /** + * Static factory method for creating an empty {@link IterateT}. + * + * @param pureM the {@link Pure} method for the effect + * @param the effect type + * @param the element type + * @return the empty {@link IterateT} + */ + public static , A> IterateT empty(Pure pureM) { + return new IterateT<>(pureM, ImmutableQueue.empty(), ImmutableQueue.empty(), ImmutableQueue.empty()); + } + + /** + * Static factory method for creating an {@link IterateT} from a single element. + * + * @param ma the element + * @param the effect type + * @param the element type + * @return the singleton {@link IterateT} + */ + public static , A> IterateT singleton(MonadRec ma) { + return new IterateT<>(Pure.of(ma), + ImmutableQueue.>empty().pushFront(ma), + ImmutableQueue.empty(), + ImmutableQueue.empty()); + } + + /** + * Static factory method for wrapping an uncons of an {@link IterateT} in an {@link IterateT}. + * + * @param unwrapped the uncons + * @param the effect type + * @param the element type + * @return the wrapped {@link IterateT} + */ + public static , A> IterateT iterateT( + MonadRec>>, M> unwrapped) { + return new IterateT<>( + Pure.of(unwrapped), + ImmutableQueue.empty(), + ImmutableQueue.>>, M>>, IterateT>>empty() + .pushFront(a(() -> unwrapped)), + ImmutableQueue.empty()); + } + + /** + * Static factory method for creating an {@link IterateT} from a spine represented by one or more elements. + * + * @param ma the head element + * @param mas the tail elements + * @param the effect type + * @param the element type + * @return the {@link IterateT} + */ + @SafeVarargs + public static , A> IterateT of( + MonadRec ma, MonadRec... mas) { + @SuppressWarnings("varargs") + List> as = asList(mas); + return foldLeft(IterateT::snoc, + empty(Pure.of(ma)), + com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons(ma, as)); + } + + /** + * Lazily unfold an {@link IterateT} from an unfolding function fn and a starting seed value + * mb by successively applying fn to the latest seed value, producing {@link Maybe maybe} + * a value to yield out and the next seed value for the subsequent computation. + * + * @param fn the unfolding function + * @param mb the starting seed value + * @param the effect type + * @param the element type + * @param the seed type + * @return the lazily unfolding {@link IterateT} + */ + public static , A, B> IterateT unfold( + Fn1>, M>> fn, MonadRec mb) { + return suspended(() -> maybeT(mb.flatMap(fn)) + .fmap(ab -> ab.fmap(b -> unfold(fn, mb.pure(b)))) + .runMaybeT(), Pure.of(mb)); + } + + /** + * Create an {@link IterateT} from a suspended computation that yields the spine of the {@link IterateT} inside the + * effect. + * + * @param thunk the suspended computation + * @param pureM the {@link Pure} method for the effect + * @param the effect type + * @param the element type + * @return the {@link IterateT} + */ + public static , A> IterateT suspended( + Fn0>>, M>> thunk, Pure pureM) { + return new IterateT<>(pureM, + ImmutableQueue.empty(), + ImmutableQueue + .>>, M>>, IterateT>>empty() + .pushFront(a(thunk)), + ImmutableQueue.empty()); + } + + /** + * Lazily unfold an {@link IterateT} from an {@link Iterator} inside {@link IO}. + * + * @param as the {@link Iterator} + * @param the element type + * @return the {@link IterateT} + */ + public static IterateT, A> fromIterator(Iterator as) { + return unfold(it -> io(() -> { + if (as.hasNext()) + return just(tuple(as.next(), as)); + return nothing(); + }), io(() -> as)); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java new file mode 100644 index 000000000..2cfc24ae0 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java @@ -0,0 +1,230 @@ +package com.jnape.palatable.lambda.monad.transformer.builtin; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.functor.builtin.Writer; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.traitor.annotations.TestTraits; +import com.jnape.palatable.traitor.framework.Subjects; +import com.jnape.palatable.traitor.runners.Traits; +import org.junit.Test; +import org.junit.runner.RunWith; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +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.Unit.UNIT; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn2.LTE.lte; +import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; +import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; +import static com.jnape.palatable.lambda.functor.builtin.Writer.listen; +import static com.jnape.palatable.lambda.functor.builtin.Writer.pureWriter; +import static com.jnape.palatable.lambda.functor.builtin.Writer.tell; +import static com.jnape.palatable.lambda.functor.builtin.Writer.writer; +import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.empty; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.singleton; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.unfold; +import static com.jnape.palatable.lambda.monoid.builtin.AddAll.addAll; +import static com.jnape.palatable.traitor.framework.Subjects.subjects; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static testsupport.Constants.STACK_EXPLODING_NUMBER; +import static testsupport.matchers.IOMatcher.yieldsValue; +import static testsupport.matchers.IterateTMatcher.isEmpty; +import static testsupport.matchers.IterateTMatcher.iterates; +import static testsupport.matchers.IterateTMatcher.iteratesAll; +import static testsupport.traits.Equivalence.equivalence; + +@RunWith(Traits.class) +public class IterateTTest { + + @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, MonadRecLaws.class}) + public Subjects, Integer>>> testSubjects() { + Fn1, ?>, Object> toCollection = iterateT -> iterateT + ., Identity>>fold( + (as, a) -> { + as.add(a); + return new Identity<>(as); + }, + new Identity<>(new ArrayList<>())) + .runIdentity(); + return subjects(equivalence(empty(pureIdentity()), toCollection), + equivalence(singleton(new Identity<>(0)), toCollection), + equivalence(IterateT., Integer>empty(pureIdentity()).cons(new Identity<>(1)), + toCollection), + equivalence(IterateT., Integer>empty(pureIdentity()).snoc(new Identity<>(1)), + toCollection), + equivalence(singleton(new Identity<>(0)).concat(singleton(new Identity<>(1))), + toCollection), + equivalence(unfold(x -> new Identity<>(x <= 100 ? just(tuple(x, x + 1)) : nothing()), + new Identity<>(0)), + toCollection) + ); + } + + @Test + public void emptyHasNoElements() { + assertEquals(new Identity<>(nothing()), + IterateT., Integer>empty(pureIdentity()) + ., Integer>>>>>runIterateT()); + } + + @Test + public void singletonHasOneElement() { + assertThat(singleton(new Identity<>(1)), iterates(1)); + } + + @Test + public void unfolding() { + assertThat(unfold(x -> new Identity<>(just(x).filter(lte(3)).fmap(y -> tuple(y, y + 1))), new Identity<>(1)), + iteratesAll(asList(1, 2, 3))); + } + + @Test + public void consAddsElementToFront() { + assertThat(singleton(new Identity<>(1)).cons(new Identity<>(0)), iterates(0, 1)); + } + + @Test + public void snocAddsElementToBack() { + assertThat(singleton(new Identity<>(1)).snoc(new Identity<>(2)), iterates(1, 2)); + } + + @Test + public void concatsTwoIterateTs() { + IterateT, Integer> front = singleton(new Identity<>(0)).snoc(new Identity<>(1)); + IterateT, Integer> back = singleton(new Identity<>(2)).snoc(new Identity<>(3)); + + assertThat(front.concat(back), iterates(0, 1, 2, 3)); + assertThat(IterateT., Integer>empty(pureIdentity()).concat(back), iterates(2, 3)); + assertThat(front.concat(empty(pureIdentity())), iterates(0, 1)); + assertThat(IterateT., Integer>empty(pureIdentity()).concat(empty(pureIdentity())), isEmpty()); + assertThat(singleton(new Identity<>(1)) + .concat(unfold(x -> new Identity<>(nothing()), new Identity<>(0))) + .concat(singleton(new Identity<>(2))), + iterates(1, 2)); + } + + @Test + public void ofIteratesElements() { + assertEquals(tuple(6, asList(1, 2, 3)), + IterateT., ?>, Integer>of(listen(1), listen(2), listen(3)) + ., Integer>>fold( + (x, y) -> writer(tuple(x + y, singletonList(y))), listen(0)) + .runWriter(addAll(ArrayList::new))); + } + + @Test + public void fromIterator() { + IterateT, Integer> it = IterateT.fromIterator(asList(1, 2, 3).iterator()); + assertThat(it., IO>>toCollection(ArrayList::new), + yieldsValue(equalTo(asList(1, 2, 3)))); + assertThat(it., IO>>toCollection(ArrayList::new), + yieldsValue(equalTo(emptyList()))); + } + + @Test + public void fold() { + assertEquals(tuple(6, asList(1, 2, 3)), + IterateT., ?>, Integer>of(listen(1), listen(2), listen(3)) + ., Integer>>fold( + (x, y) -> writer(tuple(x + y, singletonList(y))), listen(0)) + .runWriter(addAll(ArrayList::new))); + } + + @Test + public void zipUsesCartesianProduct() { + assertThat(IterateT.of(new Identity<>(1), new Identity<>(2), new Identity<>(3)) + .zip(IterateT.of(new Identity<>(x -> x + 1), new Identity<>(x -> x - 1))), + iterates(2, 3, 4, 0, 1, 2)); + } + + @Test(timeout = 1000) + public void zipsInParallel() { + CountDownLatch latch = new CountDownLatch(2); + singleton(io(() -> { + latch.countDown(); + latch.await(); + return 0; + })).zip(singleton(io(() -> { + latch.countDown(); + latch.await(); + return x -> x + 1; + })))., Integer>>>>>runIterateT() + .unsafePerformAsyncIO() + .join(); + } + + @Test + public void toCollection() { + assertEquals(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), + unfold(x -> new Identity<>(x <= 10 ? just(tuple(x, x + 1)) : nothing()), new Identity<>(1)) + ., Identity>>toCollection(ArrayList::new) + .runIdentity()); + } + + @Test + public void forEach() { + assertEquals(tuple(UNIT, asList(1, 2, 3)), + IterateT., ?>, Integer>empty(pureWriter()) + .cons(listen(3)) + .cons(listen(2)) + .cons(listen(1)) + ., Unit>>forEach(x -> tell(singletonList(x))) + .runWriter(addAll(ArrayList::new))); + } + + @Test + public void foldLargeNumberOfElements() { + IterateT, Integer> largeIterateT = times(STACK_EXPLODING_NUMBER, + it -> it.cons(new Identity<>(1)), + empty(pureIdentity())); + assertEquals(new Identity<>(STACK_EXPLODING_NUMBER), + largeIterateT.fold((x, y) -> new Identity<>(x + y), new Identity<>(0))); + } + + @Test + public void stackSafetyForStrictMonads() { + IterateT, Integer> hugeStrictIterateT = + unfold(x -> new Identity<>(x <= STACK_EXPLODING_NUMBER ? just(tuple(x, x + 1)) : nothing()), + new Identity<>(1)); + Identity fold = hugeStrictIterateT.fold((x, y) -> new Identity<>(x + y), new Identity<>(0)); + assertEquals(new Identity<>(1250025000), fold); + } + + @Test + public void stackSafetyForNonStrictMonads() { + IterateT, Integer> hugeNonStrictIterateT = + unfold(x -> lazy(() -> x <= 50_000 ? just(tuple(x, x + 1)) : nothing()), lazy(0)); + Lazy fold = hugeNonStrictIterateT.fold((x, y) -> lazy(() -> x + y), lazy(0)); + assertEquals((Integer) 1250025000, fold.value()); + } + + @Test + public void concatIsStackSafe() { + IterateT, Integer> bigIterateT = times(10_000, xs -> xs.concat(singleton(new Identity<>(1))), + singleton(new Identity<>(0))); + assertEquals(new Identity<>(10_000), + bigIterateT.fold((x, y) -> new Identity<>(x + y), new Identity<>(0))); + } +} \ No newline at end of file diff --git a/src/test/java/testsupport/matchers/IterableMatcher.java b/src/test/java/testsupport/matchers/IterableMatcher.java index f5f196aba..ac1faee71 100644 --- a/src/test/java/testsupport/matchers/IterableMatcher.java +++ b/src/test/java/testsupport/matchers/IterableMatcher.java @@ -19,7 +19,7 @@ private IterableMatcher(Iterable expected) { @Override public boolean matches(Object actual) { - return actual instanceof Iterable && iterablesIterateSameElementsInOrder(expected, (Iterable) actual); + return actual instanceof Iterable && iterablesIterateSameElementsInOrder(expected, (Iterable) actual); } @Override @@ -32,18 +32,18 @@ public void describeMismatch(Object item, Description description) { if (item instanceof Iterable) { if (description.toString().endsWith("but: ")) description.appendText("was "); - description.appendText("<").appendText(stringify((Iterable) item)).appendText(">"); + description.appendText("<").appendText(stringify((Iterable) item)).appendText(">"); } else super.describeMismatch(item, description); } private boolean iterablesIterateSameElementsInOrder(Iterable expected, Iterable actual) { - Iterator actualIterator = actual.iterator(); + Iterator actualIterator = actual.iterator(); Iterator expectedIterator = expected.iterator(); while (expectedIterator.hasNext() && actualIterator.hasNext()) { Object nextExpected = expectedIterator.next(); - Object nextActual = actualIterator.next(); + Object nextActual = actualIterator.next(); if (nextExpected instanceof Iterable && nextActual instanceof Iterable) { if (!iterablesIterateSameElementsInOrder((Iterable) nextExpected, (Iterable) nextActual)) @@ -57,11 +57,11 @@ private boolean iterablesIterateSameElementsInOrder(Iterable expected, Iterab private String stringify(Iterable iterable) { StringBuilder stringBuilder = new StringBuilder().append("["); - Iterator iterator = iterable.iterator(); + Iterator iterator = iterable.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); if (next instanceof Iterable) - stringBuilder.append(stringify((Iterable) next)); + stringBuilder.append(stringify((Iterable) next)); else stringBuilder.append(next); if (iterator.hasNext()) @@ -76,6 +76,10 @@ public static IterableMatcher iterates(E... es) { return new IterableMatcher<>(asList(es)); } + public static IterableMatcher iteratesAll(Iterable es) { + return new IterableMatcher<>(es); + } + public static IterableMatcher isEmpty() { return new IterableMatcher<>(new ArrayList<>()); } diff --git a/src/test/java/testsupport/matchers/IterateTMatcher.java b/src/test/java/testsupport/matchers/IterateTMatcher.java new file mode 100644 index 000000000..894fa6edd --- /dev/null +++ b/src/test/java/testsupport/matchers/IterateTMatcher.java @@ -0,0 +1,48 @@ +package testsupport.matchers; + +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.monad.transformer.builtin.IterateT; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; + +import java.util.LinkedList; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; + +public final class IterateTMatcher extends TypeSafeMatcher, A>> { + private final Iterable as; + + private IterateTMatcher(Iterable as) { + this.as = as; + } + + @Override + protected boolean matchesSafely(IterateT, A> iterateT) { + Identity> fold = iterateT.fold((as, a) -> { + as.add(a); + return new Identity<>(as); + }, new Identity<>(new LinkedList<>())); + LinkedList as = fold.runIdentity(); + return IterableMatcher.iteratesAll(this.as).matches(as); + } + + @Override + public void describeTo(Description description) { + description.appendText("an IterateT iterating " + as.toString() + " inside Identity"); + } + + public static IterateTMatcher iteratesAll(Iterable as) { + return new IterateTMatcher<>(as); + } + + public static IterateTMatcher isEmpty() { + return new IterateTMatcher<>(emptyList()); + } + + @SafeVarargs + @SuppressWarnings("varargs") + public static IterateTMatcher iterates(A... as) { + return iteratesAll(asList(as)); + } +} From ac2a7cd8d51e0e1398cd2de676d7a48774bd02e8 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 8 Feb 2020 16:49:19 -0600 Subject: [PATCH 296/348] Updating CHANGELOG --- CHANGELOG.md | 4 +++ .../ordering/ComparisonRelation.java | 31 +++++++++++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f53bb7d6b..8561f1f8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `MergeHMaps`, a `Monoid` that merges `HMap`s by merging the values via key-specified `Semigroup`s - `Id#id` overload that accepts an argument and returns it - `MaybeT#or`, choose the first `MaybeT` that represents an effect around `just` a value +- `MaybeT#filter`, filter a `Maybe` inside an effect - `StateMatcher, StateTMatcher, WriterTMatcher` - `ReaderT#and`, category composition between `ReaderT` instances: `(a -> m b) -> (b -> m c) -> (a -> m c)` - `IterateT`, [`ListT` done right](https://wiki.haskell.org/ListT_done_right) +- `Comparison`, a type-safe sum of `LT`, `EQ`, and `GT` orderings +- `Compare`, a function taking a `Comparator` and returning a `Comparison` +- `Min/Max/...With` variants for inequality testing with a `Comparator` ## [5.1.0] - 2019-10-13 ### Changed diff --git a/src/main/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelation.java b/src/main/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelation.java index 3878f385a..0c4bb93c3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelation.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/ordering/ComparisonRelation.java @@ -13,8 +13,14 @@ * @see Compare */ public abstract class ComparisonRelation - implements CoProduct3 { - private ComparisonRelation() { } + implements CoProduct3< + ComparisonRelation.LessThan, + ComparisonRelation.Equal, + ComparisonRelation.GreaterThan, + ComparisonRelation> { + + private ComparisonRelation() { + } /** * Return a comparison relation from the result of a {@link Comparator} or {@link Comparable} result @@ -38,7 +44,7 @@ public static Equal equal() { return Equal.INSTANCE; } - public final static class LessThan extends ComparisonRelation { + public static final class LessThan extends ComparisonRelation { private static final LessThan INSTANCE = new LessThan(); private LessThan() { @@ -50,12 +56,14 @@ public String toString() { } @Override - public R match(Fn1 aFn, Fn1 bFn, Fn1 cFn) { + public R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn) { return aFn.apply(this); } } - public final static class Equal extends ComparisonRelation { + public static final class Equal extends ComparisonRelation { private static final Equal INSTANCE = new Equal(); private Equal() { @@ -66,15 +74,18 @@ public String toString() { } @Override - public R match(Fn1 aFn, Fn1 bFn, Fn1 cFn) { + public R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn) { return bFn.apply(this); } } - public final static class GreaterThan extends ComparisonRelation { + public static final class GreaterThan extends ComparisonRelation { private static final GreaterThan INSTANCE = new GreaterThan(); - private GreaterThan() { } + private GreaterThan() { + } @Override public String toString() { @@ -82,7 +93,9 @@ public String toString() { } @Override - public R match(Fn1 aFn, Fn1 bFn, Fn1 cFn) { + public R match(Fn1 aFn, + Fn1 bFn, + Fn1 cFn) { return cFn.apply(this); } } From 90b5c8a7bb68dc453720149654cdb6ca6a419c66 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 8 Feb 2020 17:30:13 -0600 Subject: [PATCH 297/348] Adding IterateT#foldCut for folding with early termination --- .../monad/transformer/builtin/IterateT.java | 24 ++++++++++++++++--- .../transformer/builtin/IterateTTest.java | 15 ++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index 82fe5ee67..1b85133e1 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -28,7 +28,6 @@ import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; -import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; @@ -138,11 +137,30 @@ public IterateT concat(IterateT other) { */ public > MB fold(Fn2> fn, MonadRec acc) { + return foldCut((b, a) -> fn.apply(b, a).fmap(RecursiveResult::recurse), acc); + } + + /** + * Monolithically fold the spine of this {@link IterateT} (with the possibility of early termination) by + * {@link MonadRec#trampolineM(Fn1) trampolining} the underlying effects (for iterative folding, use + * {@link IterateT#trampolineM(Fn1) trampolineM} directly). + * + * @param fn the folding function + * @param acc the starting accumulation effect + * @param the accumulation type + * @param the witnessed target result type + * @return the folded effect result + */ + public > MB foldCut( + Fn2, M>> fn, + MonadRec acc) { return acc.fmap(tupler(this)) .trampolineM(into((as, b) -> maybeT(as.runIterateT()) - .flatMap(into((a, aas) -> maybeT(fn.apply(b, a).fmap(tupler(aas)).fmap(Maybe::just)))) + .flatMap(into((a, aas) -> maybeT(fn.apply(b, a).fmap(Maybe::just)).fmap(tupler(aas)))) .runMaybeT() - .fmap(maybeRecur -> maybeRecur.match(constantly(terminate(b)), RecursiveResult::recurse)))) + .fmap(maybeR -> maybeR.match( + __ -> terminate(b), + into((rest, rr) -> rr.biMapL(tupler(rest))))))) .coerce(); } diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java index 2cfc24ae0..00768b0c3 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java @@ -30,6 +30,8 @@ import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.functions.builtin.fn2.LTE.lte; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; +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.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.functor.builtin.Writer.listen; @@ -41,6 +43,7 @@ import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.singleton; import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.unfold; import static com.jnape.palatable.lambda.monoid.builtin.AddAll.addAll; +import static com.jnape.palatable.lambda.monoid.builtin.Join.join; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; @@ -152,6 +155,18 @@ public void fold() { .runWriter(addAll(ArrayList::new))); } + @Test + public void foldCut() { + assertEquals(tuple(3, "012"), + IterateT.of(writer(tuple(1, "1")), + writer(tuple(2, "2")), + writer(tuple(3, "3"))) + .>foldCut( + (x, y) -> listen(y == 2 ? terminate(x + y) : recurse(x + y)), + writer(tuple(0, "0"))) + .runWriter(join())); + } + @Test public void zipUsesCartesianProduct() { assertThat(IterateT.of(new Identity<>(1), new Identity<>(2), new Identity<>(3)) From 2dbc6f5cf923a9418aca21a9033a02eaf65f7c2d Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 8 Feb 2020 17:46:19 -0600 Subject: [PATCH 298/348] Fixing Javadocs --- .../lambda/functions/builtin/fn3/CmpEqWith.java | 16 ++++++++-------- .../lambda/functions/builtin/fn3/Compare.java | 10 +++++----- .../lambda/functions/builtin/fn3/GTEWith.java | 12 ++++++------ .../lambda/functions/builtin/fn3/LTEWith.java | 12 ++++++------ .../palatable/lambda/functor/builtin/Writer.java | 3 +++ .../monad/transformer/builtin/IterateT.java | 1 + 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWith.java index 0a0c1f1ce..ff95cd2fc 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWith.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/CmpEqWith.java @@ -11,9 +11,9 @@ import static com.jnape.palatable.lambda.functions.specialized.Predicate.predicate; /** - * Given a {@link Comparator} from some type A and two values of type A, return true - * if the first value is strictly equal to the second value (according to {@link Comparator#compare(A, A)} - * otherwise, return false. + * Given a {@link Comparator} from some type A and two values of type A, return + * true if the first value is strictly equal to the second value (according to + * {@link Comparator#compare(Object, Object)} otherwise, return false. * * @param the value type * @see CmpEqBy @@ -38,6 +38,11 @@ public Predicate apply(Comparator compareFn, A x) { return predicate(Fn3.super.apply(compareFn, x)); } + @Override + public Boolean checkedApply(Comparator comparator, A a, A a2) { + return compare(comparator, a, a2).equals(equal()); + } + @SuppressWarnings("unchecked") public static CmpEqWith cmpEqWith() { return (CmpEqWith) INSTANCE; @@ -54,9 +59,4 @@ public static Predicate cmpEqWith(Comparator comparator, A x) { public static Boolean cmpEqWith(Comparator comparator, A x, A y) { return cmpEqWith(comparator, x).apply(y); } - - @Override - public Boolean checkedApply(Comparator comparator, A a, A a2) { - return compare(comparator, a, a2).equals(equal()); - } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Compare.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Compare.java index 4f0bea533..b388feca9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Compare.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/Compare.java @@ -9,9 +9,9 @@ /** * Given a {@link Comparator} from some type A and two values of type A, return a - * {@link ComparisonRelation} of the first value with reference to the second value (according to {@link Comparator#compare(A, A)}. - * The order of parameters is flipped with respect to {@link Comparator#compare(A, A)} for more idiomatic partial application. - * + * {@link ComparisonRelation} of the first value with reference to the second value (according to + * {@link Comparator#compare(Object, Object)}. The order of parameters is flipped with respect to + * {@link Comparator#compare(Object, Object)} for more idiomatic partial application. *

* Example: *

@@ -21,7 +21,6 @@
  *  Compare.compare(naturalOrder(), 1, 1); // ComparisonRelation.Equal
  * }
  * 
- *

* * @param
the value type * @see Comparator @@ -30,7 +29,8 @@ public final class Compare implements Fn3, A, A, ComparisonRelation> { private static final Compare INSTANCE = new Compare<>(); - private Compare() { } + private Compare() { + } @Override public ComparisonRelation checkedApply(Comparator aComparator, A a, A a2) throws Throwable { diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWith.java index 7a3c8cc6d..29a5dfe82 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWith.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/GTEWith.java @@ -13,7 +13,7 @@ /** * Given a {@link Comparator} from some type A and two values of type A, * return true if the second value is greater than or equal to the first value in - * terms of their mapped B results according to {@link Comparator#compare(A, A)}; + * terms of their mapped B results according to {@link Comparator#compare(Object, Object)}; * otherwise, return false. * * @param the value type @@ -38,6 +38,11 @@ public Predicate apply(Comparator compareFn, A x) { return predicate(Fn3.super.apply(compareFn, x)); } + @Override + public Boolean checkedApply(Comparator comparator, A a, A a2) { + return !ltWith(comparator, a, a2); + } + @SuppressWarnings("unchecked") public static GTEWith gteWith() { return (GTEWith) INSTANCE; @@ -54,9 +59,4 @@ public static Predicate gteWith(Comparator comparator, A y) { public static Boolean gteWith(Comparator comparator, A y, A x) { return gteWith(comparator, y).apply(x); } - - @Override - public Boolean checkedApply(Comparator comparator, A a, A a2) { - return !ltWith(comparator, a, a2); - } } diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWith.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWith.java index 06e621d3f..403f5c15f 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWith.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn3/LTEWith.java @@ -13,7 +13,7 @@ /** * Given a {@link Comparator} from some type A and two values of type A, * return true if the second value is less than or equal to the first value in - * terms of their mapped B results according to {@link Comparator#compare(A, A)}; + * terms of their mapped B results according to {@link Comparator#compare(Object, Object)}; * otherwise, return false. * * @param the value type @@ -38,6 +38,11 @@ public Predicate apply(Comparator compareFn, A x) { return predicate(Fn3.super.apply(compareFn, x)); } + @Override + public Boolean checkedApply(Comparator comparator, A a, A a2) { + return !gtWith(comparator, a, a2); + } + @SuppressWarnings("unchecked") public static LTEWith lteWith() { return (LTEWith) INSTANCE; @@ -54,9 +59,4 @@ public static Predicate lteWith(Comparator comparator, A y) { public static Boolean lteWith(Comparator comparator, A y, A x) { return lteWith(comparator, y).apply(x); } - - @Override - public Boolean checkedApply(Comparator comparator, A a, A a2) { - return !gtWith(comparator, a, a2); - } } diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Writer.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Writer.java index bb00cb402..c4c6d752d 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Writer.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Writer.java @@ -136,6 +136,7 @@ public Writer discardR(Applicative> appB) { /** * Construct a {@link Writer} from an accumulation. * + * @param w the accumulation * @param the accumulation type * @return the {@link Writer} */ @@ -146,6 +147,7 @@ public static Writer tell(W w) { /** * Construct a {@link Writer} from a value. * + * @param a the output value * @param the accumulation type * @param the value type * @return the {@link Writer} @@ -157,6 +159,7 @@ public static Writer listen(A a) { /** * Construct a {@link Writer} from an accumulation and a value. * + * @param aw the output value and accumulation * @param the accumulation type * @param the value type * @return the {@link WriterT} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index 1b85133e1..606e7d894 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -230,6 +230,7 @@ public IterateT pure(B b) { * as such, calling this on an infinite {@link IterateT} will result in either heap exhaustion (e.g. in the case of * {@link List lists}) or non-termination (e.g. in the case of {@link Set sets}). * + * @param cFn0 the {@link Collection} construction function * @param the {@link Collection} type * @param the witnessed target type * @return the {@link List} inside of the effect From 47eba89d04479d052608046054466f9d481de4a9 Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 8 Feb 2020 17:58:06 -0600 Subject: [PATCH 299/348] [maven-release-plugin] prepare release lambda-5.2.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5f84c2dd2..f89d14be0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.1.1-SNAPSHOT + 5.2.0 jar Lambda From f30d63fb5c5367aba49b2e319fef50788504553a Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 8 Feb 2020 17:58:13 -0600 Subject: [PATCH 300/348] [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 f89d14be0..bda3d7caf 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.2.0 + 5.2.1-SNAPSHOT jar Lambda From a04ea83f02819aa219c61d07d05352d9365fb27f Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 12 Feb 2020 18:17:05 -0600 Subject: [PATCH 301/348] Updating README and CHANGELOG --- CHANGELOG.md | 7 ++++++- README.md | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8561f1f8f..1ce4e47aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] +There are currently no unreleased changes + +## [5.2.0] - 2020-02-12 + ### Changed - `HList#cons` static factory method auto-promotes to specialized `HList` if there is one - `EitherT` gains a `MonadError` instance @@ -557,7 +561,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-5.1.0...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-5.2.0...HEAD +[5.2.0]: https://github.com/palatable/lambda/compare/lambda-5.1.0...lambda-5.2.0 [5.1.0]: https://github.com/palatable/lambda/compare/lambda-5.0.0...lambda-5.1.0 [5.0.0]: https://github.com/palatable/lambda/compare/lambda-4.0.0...lambda-5.0.0 [4.0.0]: https://github.com/palatable/lambda/compare/lambda-3.3.0...lambda-4.0.0 diff --git a/README.md b/README.md index edaf4dde9..312d220fb 100644 --- a/README.md +++ b/README.md @@ -61,14 +61,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 5.1.0 + 5.2.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '5.1.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '5.2.0' ``` Examples From 24658def4d150ce13e0c3ff7073a8612cd21d42f Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 21 Feb 2020 15:44:30 -0600 Subject: [PATCH 302/348] Adding static Pure and Lift instances for IterateT --- .../monad/transformer/builtin/IterateT.java | 26 ++++++++++++++ .../transformer/builtin/IterateTTest.java | 35 +++++++++++-------- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index 606e7d894..e4197b98d 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -8,6 +8,7 @@ import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.Fn2; import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; +import com.jnape.palatable.lambda.functions.specialized.Lift; import com.jnape.palatable.lambda.functions.specialized.Pure; import com.jnape.palatable.lambda.functor.Applicative; import com.jnape.palatable.lambda.functor.builtin.Lazy; @@ -451,4 +452,29 @@ public static IterateT, A> fromIterator(Iterator as) { return nothing(); }), io(() -> as)); } + + /** + * The canonical {@link Pure} instance for {@link IterateT}. + * + * @param pureM the argument {@link Monad} {@link Pure} + * @param the argument {@link Monad} witness + * @return the {@link Pure} instance + */ + public static > Pure> pureIterateT(Pure pureM) { + return new Pure>() { + @Override + public IterateT checkedApply(A a) { + return liftIterateT().apply(pureM.>apply(a)); + } + }; + } + + /** + * {@link Lift} for {@link IterateT}. + * + * @return the {@link Monad} lifted into {@link IterateT} + */ + public static Lift> liftIterateT() { + return IterateT::singleton; + } } diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java index 00768b0c3..b74e93835 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java @@ -13,11 +13,7 @@ import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.traits.ApplicativeLaws; -import testsupport.traits.Equivalence; -import testsupport.traits.FunctorLaws; -import testsupport.traits.MonadLaws; -import testsupport.traits.MonadRecLaws; +import testsupport.traits.*; import java.util.ArrayList; import java.util.Collection; @@ -34,14 +30,9 @@ import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; -import static com.jnape.palatable.lambda.functor.builtin.Writer.listen; -import static com.jnape.palatable.lambda.functor.builtin.Writer.pureWriter; -import static com.jnape.palatable.lambda.functor.builtin.Writer.tell; -import static com.jnape.palatable.lambda.functor.builtin.Writer.writer; +import static com.jnape.palatable.lambda.functor.builtin.Writer.*; import static com.jnape.palatable.lambda.io.IO.io; -import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.empty; -import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.singleton; -import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.unfold; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.*; import static com.jnape.palatable.lambda.monoid.builtin.AddAll.addAll; import static com.jnape.palatable.lambda.monoid.builtin.Join.join; import static com.jnape.palatable.traitor.framework.Subjects.subjects; @@ -53,9 +44,7 @@ import static org.junit.Assert.assertThat; import static testsupport.Constants.STACK_EXPLODING_NUMBER; import static testsupport.matchers.IOMatcher.yieldsValue; -import static testsupport.matchers.IterateTMatcher.isEmpty; -import static testsupport.matchers.IterateTMatcher.iterates; -import static testsupport.matchers.IterateTMatcher.iteratesAll; +import static testsupport.matchers.IterateTMatcher.*; import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) @@ -242,4 +231,20 @@ public void concatIsStackSafe() { assertEquals(new Identity<>(10_000), bigIterateT.fold((x, y) -> new Identity<>(x + y), new Identity<>(0))); } + + @Test + public void staticPure() { + assertEquals(new Identity<>(singletonList(1)), + pureIterateT(pureIdentity()) + ., Integer>>apply(1) + ., Identity>>toCollection(ArrayList::new)); + } + + @Test + public void staticLift() { + assertEquals(new Identity<>(singletonList(1)), + liftIterateT() + ., IterateT, Integer>>apply(new Identity<>(1)) + ., Identity>>toCollection(ArrayList::new)); + } } \ No newline at end of file From 5cc409441d391d1fa1614000f82e7129350faaac Mon Sep 17 00:00:00 2001 From: John Napier Date: Mon, 23 Mar 2020 15:52:38 -0500 Subject: [PATCH 303/348] Attempting to add JDK14 build to github actions --- .github/workflows/maven.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 2f7615ccb..873d5ac83 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -28,3 +28,16 @@ jobs: java-version: 11 - name: Build with Maven run: mvn clean verify + + build-java-14: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 14 + uses: actions/setup-java@v1 + with: + java-version: 14 + - name: Build with Maven + run: mvn clean verify From 28f92b412d357e6516d3002ef816fb00c90ad685 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 1 Apr 2020 14:34:23 -0500 Subject: [PATCH 304/348] Adding $, function application represented as a higher-order Fn2 --- CHANGELOG.md | 3 +- .../lambda/functions/builtin/fn2/$.java | 43 +++++++++++++++++++ .../lambda/functions/builtin/fn2/$Test.java | 21 +++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/$.java create mode 100644 src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/$Test.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ce4e47aa..885221573 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] -There are currently no unreleased changes +### Added +- `$`, function application represented as a higher-order `Fn2` ## [5.2.0] - 2020-02-12 diff --git a/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/$.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/$.java new file mode 100644 index 000000000..63c60c051 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/$.java @@ -0,0 +1,43 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functions.Fn2; + +/** + * Function application, represented as a higher-order {@link Fn2} that receives an {@link Fn1} and its argument, and + * applies it. Useful for treating application as a combinator, e.g.: + *
+ * {@code
+ * List> fns     = asList(x -> x + 1, x -> x, x -> x - 1);
+ * List               args    = asList(0, 1, 2);
+ * Iterable           results = zipWith($(), fns, args); // [1, 1, 1]
+ * }
+ * 
+ * + * @param
the applied {@link Fn1 Fn1's} input type + * @param the applied {@link Fn1 Fn1's} output type + */ +public final class $ implements Fn2, A, B> { + private static final $ INSTANCE = new $<>(); + + private $() { + } + + @Override + public B checkedApply(Fn1 fn, A a) { + return fn.apply(a); + } + + @SuppressWarnings("unchecked") + public static $ $() { + return ($) INSTANCE; + } + + public static Fn1 $(Fn1 fn) { + return $.$().apply(fn); + } + + public static B $(Fn1 fn, A a) { + return $.$(fn).apply(a); + } +} diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/$Test.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/$Test.java new file mode 100644 index 000000000..166e99f29 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/$Test.java @@ -0,0 +1,21 @@ +package com.jnape.palatable.lambda.functions.builtin.fn2; + +import org.junit.Test; + +import static com.jnape.palatable.lambda.functions.Fn2.fn2; +import static com.jnape.palatable.lambda.functions.builtin.fn2.$.$; +import static org.junit.Assert.assertEquals; + +public class $Test { + + @Test + public void application() { + assertEquals((Integer) 1, $(x -> x + 1, 0)); + assertEquals((Integer) 1, $.$(x -> x + 1).apply(0)); + } + + @Test + public void curryingInference() { + assertEquals((Integer) 1, $($(fn2(Integer::sum), 0), 1)); + } +} \ No newline at end of file From e9a98fc6ef6db5b1c2ac4c892adb9deebabb073f Mon Sep 17 00:00:00 2001 From: Joshua Potts <8704475+iamjpotts@users.noreply.github.com> Date: Sun, 12 Apr 2020 23:36:51 -0500 Subject: [PATCH 305/348] Adjust documentation for Fn7 and Fn8 --- src/main/java/com/jnape/palatable/lambda/functions/Fn7.java | 2 +- src/main/java/com/jnape/palatable/lambda/functions/Fn8.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index 2d27e6be2..88044dff1 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -8,7 +8,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; /** - * A function taking six arguments. Defined in terms of {@link Fn6}, so similarly auto-curried. + * A function taking seven arguments. Defined in terms of {@link Fn6}, so similarly auto-curried. * * @param The first argument type * @param The second argument type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java index a38e74eb1..c2b8fab52 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java @@ -5,7 +5,7 @@ import com.jnape.palatable.lambda.internal.Runtime; /** - * A function taking six arguments. Defined in terms of {@link Fn7}, so similarly auto-curried. + * A function taking eight arguments. Defined in terms of {@link Fn7}, so similarly auto-curried. * * @param The first argument type * @param The second argument type From 10a229b7fc3b88c2d6bd37ec45f877aefaf37864 Mon Sep 17 00:00:00 2001 From: Joshua Potts <8704475+iamjpotts@users.noreply.github.com> Date: Tue, 14 Apr 2020 22:17:54 -0500 Subject: [PATCH 306/348] Adjust documentation for Fn7 and Fn8 --- src/main/java/com/jnape/palatable/lambda/functions/Fn7.java | 4 ++-- src/main/java/com/jnape/palatable/lambda/functions/Fn8.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java index 88044dff1..15f7a3be9 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn7.java @@ -258,7 +258,7 @@ static Fn7 fn7(Fn4 the first input argument type * @param the second input argument type * @param the third input argument type @@ -276,7 +276,7 @@ static Fn7 fn7(Fn5 the first input argument type * @param the second input argument type * @param the third input argument type diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java index c2b8fab52..60f3a4a3c 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn8.java @@ -274,7 +274,7 @@ static Fn8 fn8( /** * Static factory method for wrapping a curried {@link Fn5} in an {@link Fn8}. * - * @param curriedFn5 the curried fn4 to adapt + * @param curriedFn5 the curried fn5 to adapt * @param the first input argument type * @param the second input argument type * @param the third input argument type @@ -294,7 +294,7 @@ static Fn8 fn8( /** * Static factory method for wrapping a curried {@link Fn6} in an {@link Fn8}. * - * @param curriedFn6 the curried fn4 to adapt + * @param curriedFn6 the curried fn6 to adapt * @param the first input argument type * @param the second input argument type * @param the third input argument type @@ -314,7 +314,7 @@ static Fn8 fn8( /** * Static factory method for wrapping a curried {@link Fn7} in an {@link Fn8}. * - * @param curriedFn7 the curried fn4 to adapt + * @param curriedFn7 the curried fn7 to adapt * @param the first input argument type * @param the second input argument type * @param the third input argument type From 3e6f644320bfe0a06f8207f3e2ff5b9d38c0688f Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 22 Apr 2020 17:26:51 -0500 Subject: [PATCH 307/348] Fn1#withSelf for writing self-referencing Fn1s --- CHANGELOG.md | 1 + .../jnape/palatable/lambda/functions/Fn1.java | 17 +++++++++++++++++ .../palatable/lambda/functions/Fn1Test.java | 7 ++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 885221573..c0b802288 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `$`, function application represented as a higher-order `Fn2` +- `Fn1#withSelf`, a static method for constructing a self-referencing `Fn1` ## [5.2.0] - 2020-02-12 diff --git a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java index f21e70e23..cb4904d35 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn1.java @@ -302,6 +302,10 @@ default Fn2 andThen(Fn2 after return (a, c) -> after.apply(apply(a), c); } + default Fn1 self() { + return this; + } + /** * Static factory method for avoid explicit casting when using method references as {@link Fn1}s. * @@ -335,4 +339,17 @@ static Fn1 fromFunction(Function function) static Pure> pureFn1() { return Constantly::constantly; } + + /** + * Construct an {@link Fn1} that has a reference to itself in scope at the time it is executed (presumably for + * recursive invocations). + * + * @param fn the body of the function, with access to itself + * @param the input type + * @param the output type + * @return the {@link Fn1} + */ + static Fn1 withSelf(Fn2, ? super A, ? extends B> fn) { + return a -> fn.apply(withSelf(fn), a); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java index 39400c6b0..047aea1db 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/Fn1Test.java @@ -8,8 +8,8 @@ import testsupport.traits.Equivalence; import testsupport.traits.FunctorLaws; import testsupport.traits.MonadLaws; -import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadReaderLaws; +import testsupport.traits.MonadRecLaws; import testsupport.traits.MonadWriterLaws; import java.util.function.Function; @@ -105,4 +105,9 @@ public void staticPure() { Fn1 fn1 = Fn1.pureFn1().apply(1); assertEquals((Integer) 1, fn1.apply("anything")); } + + @Test + public void withSelf() { + assertEquals((Integer) 15, Fn1.withSelf((f, x) -> x > 1 ? x + f.apply(x - 1) : x).apply(5)); + } } From 27068677d6b0e9ac0665cecb72a209beee43c5e0 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 22 Apr 2020 17:27:38 -0500 Subject: [PATCH 308/348] IterateT#unfold now only constructs one Pure instance at invocation time --- .../monad/transformer/builtin/IterateT.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index e4197b98d..07ea19982 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -29,6 +29,8 @@ import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn1.withSelf; +import static com.jnape.palatable.lambda.functions.builtin.fn2.$.$; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; import static com.jnape.palatable.lambda.functions.builtin.fn2.Tupler2.tupler; import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldLeft.foldLeft; @@ -74,10 +76,10 @@ private IterateT(Pure pureM, ImmutableQueue> conses, ImmutableQueue>>, M>>, IterateT>> middles, ImmutableQueue> snocs) { - this.pureM = pureM; - this.conses = conses; + this.pureM = pureM; + this.conses = conses; this.middles = middles; - this.snocs = snocs; + this.snocs = snocs; } /** @@ -220,7 +222,7 @@ public IterateT fmap(Fn1 fn) { */ @Override public IterateT pure(B b) { - return singleton(runIterateT().pure(b)); + return singleton(pureM.>apply(b)); } /** @@ -413,9 +415,10 @@ public static , A> IterateT of( */ public static , A, B> IterateT unfold( Fn1>, M>> fn, MonadRec mb) { - return suspended(() -> maybeT(mb.flatMap(fn)) - .fmap(ab -> ab.fmap(b -> unfold(fn, mb.pure(b)))) - .runMaybeT(), Pure.of(mb)); + Pure pureM = Pure.of(mb); + return $(withSelf((self, mmb) -> suspended(() -> maybeT(mmb.flatMap(fn)) + .fmap(ab -> ab.>fmap(b -> self.apply(pureM.apply(b)))) + .runMaybeT(), pureM)), mb); } /** From 66b045930be1fc1c18ddced61bca23e42f4a3ce7 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 22 Apr 2020 18:12:14 -0500 Subject: [PATCH 309/348] Updating CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0b802288..281562d22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] +### Changed +- `IterateT#unfold` now only computes a single `Pure` for the given input + ### Added - `$`, function application represented as a higher-order `Fn2` - `Fn1#withSelf`, a static method for constructing a self-referencing `Fn1` From 7ec5690d53e20ef6cde3e70b128c50f27650e46c Mon Sep 17 00:00:00 2001 From: Joshua Potts <8704475+iamjpotts@users.noreply.github.com> Date: Tue, 14 Apr 2020 20:32:53 -0500 Subject: [PATCH 310/348] Add snoc to HNil, SingletonHList, and Tuple classes --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/adt/hlist/HList.java | 11 +++++++++++ .../palatable/lambda/adt/hlist/SingletonHList.java | 11 +++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple2.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple3.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple4.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple5.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple6.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple7.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple8.java | 10 ++++++++++ .../jnape/palatable/lambda/adt/hlist/HListTest.java | 6 ++++++ .../lambda/adt/hlist/SingletonHListTest.java | 7 +++++++ .../jnape/palatable/lambda/adt/hlist/Tuple2Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple3Test.java | 9 +++++++++ .../jnape/palatable/lambda/adt/hlist/Tuple4Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple5Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple6Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple7Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple8Test.java | 9 +++++++++ 19 files changed, 154 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 281562d22..e96c8697d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Added - `$`, function application represented as a higher-order `Fn2` - `Fn1#withSelf`, a static method for constructing a self-referencing `Fn1` +- `HNil/SingletonHList/TupleX#snoc`, a method to add a new last element (append to a tuple) ## [5.2.0] - 2020-02-12 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 421855a10..897f19c05 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 @@ -297,5 +297,16 @@ private HNil() { public SingletonHList cons(Head head) { return new SingletonHList<>(head); } + + /** + * Snoc an element onto the back of this HList. + * + * @param last the new last element + * @param the new last element type + * @return the updated HList + */ + public SingletonHList snoc(Last last) { + return new SingletonHList<>(last); + } } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index 927f27ae3..79b3fbc87 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -39,6 +39,17 @@ public <_0> Tuple2<_0, _1> cons(_0 _0) { return new Tuple2<>(_0, this); } + + /** + * Snoc an element onto the back of this HList. + * + * @param _2 the new last element + * @return the updated HList + */ + public <_2> Tuple2<_1, _2> snoc(_2 _2) { + return tuple(head(), _2); + } + /** * {@inheritDoc} */ 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 726335f6d..b08d096f2 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 @@ -75,6 +75,16 @@ public <_0> Tuple3<_0, _1, _2> cons(_0 _0) { return new Tuple3<>(_0, this); } + /** + * Snoc an element onto the back of this HList. + * + * @param _3 the new last element + * @return the updated HList + */ + public <_3> Tuple3<_1, _2, _3> snoc(_3 _3) { + return tuple(_1, _2, _3); + } + /** * {@inheritDoc} */ 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 e32eac589..48fd309a4 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 @@ -56,6 +56,16 @@ public <_0> Tuple4<_0, _1, _2, _3> cons(_0 _0) { return new Tuple4<>(_0, this); } + /** + * Snoc an element onto the back of this HList. + * + * @param _4 the new last element + * @return the updated HList + */ + public <_4> Tuple4<_1, _2, _3, _4> snoc(_4 _4) { + return tuple(_1, _2, _3, _4); + } + /** * {@inheritDoc} */ 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 3e74da859..f8b630aa5 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 @@ -59,6 +59,16 @@ public <_0> Tuple5<_0, _1, _2, _3, _4> cons(_0 _0) { return new Tuple5<>(_0, this); } + /** + * Snoc an element onto the back of this HList. + * + * @param _5 the new last element + * @return the updated HList + */ + public <_5> Tuple5<_1, _2, _3, _4, _5> snoc(_5 _5) { + return tuple(_1, _2, _3, _4, _5); + } + /** * {@inheritDoc} */ 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 c87ee564b..e7a2c7877 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 @@ -62,6 +62,16 @@ public <_0> Tuple6<_0, _1, _2, _3, _4, _5> cons(_0 _0) { return new Tuple6<>(_0, this); } + /** + * Snoc an element onto the back of this HList. + * + * @param _6 the new last element + * @return the updated HList + */ + public <_6> Tuple6<_1, _2, _3, _4, _5, _6> snoc(_6 _6) { + return tuple(_1, _2, _3, _4, _5, _6); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 6d07b503b..ca65c7793 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -66,6 +66,16 @@ public <_0> Tuple7<_0, _1, _2, _3, _4, _5, _6> cons(_0 _0) { return new Tuple7<>(_0, this); } + /** + * Snoc an element onto the back of this HList. + * + * @param _7 the new last element + * @return the updated HList + */ + public <_7> Tuple7<_1, _2, _3, _4, _5, _6, _7> snoc(_7 _7) { + return tuple(_1, _2, _3, _4, _5, _6, _7); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index a3e162f73..61f4edf63 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -70,6 +70,16 @@ public <_0> Tuple8<_0, _1, _2, _3, _4, _5, _6, _7> cons(_0 _0) { return new Tuple8<>(_0, this); } + /** + * Snoc an element onto the back of this HList. + * + * @param _8 the new last element + * @return the updated HList + */ + public <_8> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> snoc(_8 _8) { + return tuple(_1, _2, _3, _4, _5, _6, _7, _8); + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index 8a8001e24..fd6f3d8d0 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -74,6 +74,16 @@ public <_0> HCons<_0, Tuple8<_1, _2, _3, _4, _5, _6, _7, _8>> cons(_0 _0) { return new HCons<>(_0, this); } + /** + * Snoc an element onto the back of this HList. + * + * @param _9 the new last element + * @return the updated HList + */ + public <_9> HCons<_1, Tuple8<_2, _3, _4, _5, _6, _7, _8, _9>> snoc(_9 _9) { + return singletonHList(_9).cons(_8).cons(_7).cons(_6).cons(_5).cons(_4).cons(_3).cons(_2).cons(_1); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java index 1f75ce450..09e9e44d0 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java @@ -68,4 +68,10 @@ public void hashCodeUsesDecentDistribution() { assertNotEquals(nil().cons(1).hashCode(), nil().cons(2).hashCode()); assertNotEquals(nil().cons(1).cons(2).hashCode(), nil().cons(1).cons(3).hashCode()); } + + @Test + public void snoc() { + SingletonHList tuple = nil().snoc((float) 4.0); + assertEquals(4.0, tuple.head(), 0.01); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java index 57a9f85b7..6d7d8c0b2 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java @@ -13,6 +13,7 @@ import static com.jnape.palatable.lambda.adt.hlist.HList.nil; import static com.jnape.palatable.lambda.adt.hlist.HList.singletonHList; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static com.jnape.palatable.lambda.adt.hlist.SingletonHList.pureSingletonHList; import static org.junit.Assert.assertEquals; @@ -56,4 +57,10 @@ public void staticPure() { SingletonHList singletonHList = pureSingletonHList().apply(1); assertEquals(singletonHList(1), singletonHList); } + + @Test + public void snoc() { + Tuple2 tuple = singletonHList((byte) 127).snoc('x'); + assertEquals(tuple((byte) 127, 'x'), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index 32483a168..ce28b964b 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -143,4 +143,10 @@ public void staticPure() { Tuple2 tuple = pureTuple(1).apply("two"); assertEquals(tuple(1, "two"), tuple); } + + @Test + public void snoc() { + Tuple3 tuple = tuple(Long.MAX_VALUE, 123).snoc("hi"); + assertEquals(tuple(Long.MAX_VALUE, 123, "hi"), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java index 9ac57fcfb..aa25c3e59 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java @@ -13,11 +13,14 @@ import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; +import java.time.Duration; + 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.hlist.Tuple3.pureTuple; import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; +import static java.time.Duration.ofSeconds; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; @@ -119,4 +122,10 @@ public void staticPure() { Tuple3 tuple = pureTuple(1, "2").apply('3'); assertEquals(tuple(1, "2", '3'), tuple); } + + @Test + public void snoc() { + Tuple4 tuple = tuple("qux", Long.MIN_VALUE, 7).snoc(ofSeconds(13)); + assertEquals(tuple("qux", Long.MIN_VALUE, 7, ofSeconds(13)), tuple); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java index b2a1d6319..a0b27f05e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java @@ -122,4 +122,10 @@ public void staticPure() { Tuple4 tuple = pureTuple(1, "2", '3').apply(true); assertEquals(tuple(1, "2", '3', true), tuple); } + + @Test + public void snoc() { + Tuple5 tuple = tuple("qux", 7, "foo", 13L).snoc(17); + assertEquals(tuple("qux", 7, "foo", 13L, 17), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index 83b300b97..ee0d6b7be 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -128,4 +128,10 @@ public void staticPure() { Tuple5 tuple = pureTuple(1, "2", '3', true).apply(5f); assertEquals(tuple(1, "2", '3', true, 5f), tuple); } + + @Test + public void snoc() { + Tuple6 tuple = tuple("a", 5, "b", 7, "c").snoc(11); + assertEquals(tuple("a", 5, "b", 7, "c", 11), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index 902b4b254..dd57fde9c 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -132,4 +132,10 @@ public void staticPure() { Tuple6 tuple = pureTuple(1, "2", '3', true, 5f).apply((byte) 6); assertEquals(tuple(1, "2", '3', true, 5f, (byte) 6), tuple); } + + @Test + public void snoc() { + Tuple7 tuple = tuple(5L, "a", 7, "b", 11, "c").snoc(13); + assertEquals(tuple(5L, "a", 7, "b", 11, "c", 13), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index 0e8a68aec..14ccb30a6 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -136,4 +136,10 @@ public void staticPure() { pureTuple((byte) 1, (short) 2, 3, 4L, 5F, 6D).apply(true); assertEquals(tuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true), tuple); } + + @Test + public void snoc() { + Tuple8 tuple = tuple("b", 7L, "c", 11, "d", 13, "e").snoc('f'); + assertEquals(tuple("b", 7L, "c", 11, "d", 13, "e", 'f'), tuple); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java index 4d2a8cb76..33921079e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java @@ -14,6 +14,8 @@ import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; +import java.time.LocalDate; + 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; @@ -147,4 +149,11 @@ public void staticPure() { pureTuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true).apply('8'); assertEquals(tuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true, '8'), tuple); } + + @Test + public void snoc() { + HCons> actual = tuple("b", 7L, "c", 11, "d", 13, "e", 15L).snoc(LocalDate.of(2020, 4, 14)); + assertEquals("b", actual.head()); + assertEquals(actual.tail(), tuple(7L, "c", 11, "d", 13, "e", 15L, LocalDate.of(2020, 4, 14))); + } } \ No newline at end of file From 8e95a1d09e4df6e07024a26b38107bd936712f3f Mon Sep 17 00:00:00 2001 From: jnape Date: Thu, 18 Jun 2020 11:23:09 -0500 Subject: [PATCH 311/348] Updating javadoc, reorganizing code, dropping HNil#snoc --- .../palatable/lambda/adt/hlist/HList.java | 20 +------------ .../lambda/adt/hlist/SingletonHList.java | 5 ++-- .../palatable/lambda/adt/hlist/Tuple2.java | 7 +++-- .../palatable/lambda/adt/hlist/Tuple3.java | 9 +++--- .../palatable/lambda/adt/hlist/Tuple4.java | 11 +++---- .../palatable/lambda/adt/hlist/Tuple5.java | 13 +++++---- .../palatable/lambda/adt/hlist/Tuple6.java | 15 +++++----- .../palatable/lambda/adt/hlist/Tuple7.java | 17 ++++++----- .../palatable/lambda/adt/hlist/Tuple8.java | 19 ++++++------ .../palatable/lambda/adt/hlist/HListTest.java | 29 +++++++++---------- .../lambda/adt/hlist/SingletonHListTest.java | 11 ++++--- .../lambda/adt/hlist/Tuple2Test.java | 11 ++++--- .../lambda/adt/hlist/Tuple3Test.java | 14 ++++----- .../lambda/adt/hlist/Tuple4Test.java | 11 ++++--- .../lambda/adt/hlist/Tuple5Test.java | 11 ++++--- .../lambda/adt/hlist/Tuple6Test.java | 11 ++++--- .../lambda/adt/hlist/Tuple7Test.java | 11 ++++--- .../lambda/adt/hlist/Tuple8Test.java | 16 +++++----- 18 files changed, 112 insertions(+), 129 deletions(-) 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 897f19c05..705e43bad 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 @@ -89,7 +89,6 @@ public static SingletonHList singletonHList(Head head) { * @return the 2-element HList * @see Tuple2 */ - @SuppressWarnings("JavaDoc") public static <_1, _2> Tuple2<_1, _2> tuple(_1 _1, _2 _2) { return singletonHList(_2).cons(_1); } @@ -106,7 +105,6 @@ public static <_1, _2> Tuple2<_1, _2> tuple(_1 _1, _2 _2) { * @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); } @@ -125,7 +123,6 @@ public static <_1, _2, _3> Tuple3<_1, _2, _3> tuple(_1 _1, _2 _2, _3 _3) { * @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); } @@ -146,7 +143,6 @@ public static <_1, _2, _3, _4> Tuple4<_1, _2, _3, _4> tuple(_1 _1, _2 _2, _3 _3, * @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); } @@ -169,7 +165,6 @@ public static <_1, _2, _3, _4, _5> Tuple5<_1, _2, _3, _4, _5> tuple(_1 _1, _2 _2 * @return the 6-element HList * @see Tuple6 */ - @SuppressWarnings("JavaDoc") public static <_1, _2, _3, _4, _5, _6> Tuple6<_1, _2, _3, _4, _5, _6> tuple(_1 _1, _2 _2, _3 _3, _4 _4, _5 _5, _6 _6) { return tuple(_2, _3, _4, _5, _6).cons(_1); @@ -195,7 +190,6 @@ public static <_1, _2, _3, _4, _5, _6> Tuple6<_1, _2, _3, _4, _5, _6> tuple(_1 _ * @return the 7-element HList * @see Tuple7 */ - @SuppressWarnings("JavaDoc") public static <_1, _2, _3, _4, _5, _6, _7> Tuple7<_1, _2, _3, _4, _5, _6, _7> tuple(_1 _1, _2 _2, _3 _3, _4 _4, _5 _5, _6 _6, _7 _7) { return tuple(_2, _3, _4, _5, _6, _7).cons(_1); @@ -223,7 +217,6 @@ public static <_1, _2, _3, _4, _5, _6, _7> Tuple7<_1, _2, _3, _4, _5, _6, _7> tu * @return the 8-element HList * @see Tuple8 */ - @SuppressWarnings("JavaDoc") public static <_1, _2, _3, _4, _5, _6, _7, _8> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> tuple(_1 _1, _2 _2, _3 _3, _4 _4, _5 _5, _6 _6, _7 _7, _8 _8) { @@ -273,7 +266,7 @@ public final boolean equals(Object other) { if (other instanceof HCons) { HCons that = (HCons) other; return this.head.equals(that.head) - && this.tail.equals(that.tail); + && this.tail.equals(that.tail); } return false; } @@ -297,16 +290,5 @@ private HNil() { public SingletonHList cons(Head head) { return new SingletonHList<>(head); } - - /** - * Snoc an element onto the back of this HList. - * - * @param last the new last element - * @param the new last element type - * @return the updated HList - */ - public SingletonHList snoc(Last last) { - return new SingletonHList<>(last); - } } } diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java index 79b3fbc87..8e8516a47 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/SingletonHList.java @@ -41,10 +41,11 @@ public <_0> Tuple2<_0, _1> cons(_0 _0) { /** - * Snoc an element onto the back of this HList. + * Snoc an element onto the back of this {@link SingletonHList}. * * @param _2 the new last element - * @return the updated HList + * @param <_2> the new last element type + * @return the new {@link Tuple2} */ public <_2> Tuple2<_1, _2> snoc(_2 _2) { return tuple(head(), _2); 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 b08d096f2..cdf79be12 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 @@ -48,7 +48,7 @@ public class Tuple2<_1, _2> extends HCons<_1, SingletonHList<_2>> implements Tuple2(_1 _1, SingletonHList<_2> tail) { super(_1, tail); this._1 = _1; - _2 = tail.head(); + _2 = tail.head(); } /** @@ -76,10 +76,11 @@ public <_0> Tuple3<_0, _1, _2> cons(_0 _0) { } /** - * Snoc an element onto the back of this HList. + * Snoc an element onto the back of this {@link Tuple2}. * * @param _3 the new last element - * @return the updated HList + * @param <_3> the new last element type + * @return the new {@link Tuple3} */ public <_3> Tuple3<_1, _2, _3> snoc(_3 _3) { return tuple(_1, _2, _3); 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 48fd309a4..6fe7710b3 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 @@ -44,8 +44,8 @@ public class Tuple3<_1, _2, _3> extends HCons<_1, Tuple2<_2, _3>> implements Tuple3(_1 _1, Tuple2<_2, _3> tail) { super(_1, tail); this._1 = _1; - _2 = tail._1(); - _3 = tail._2(); + _2 = tail._1(); + _3 = tail._2(); } /** @@ -57,10 +57,11 @@ public <_0> Tuple4<_0, _1, _2, _3> cons(_0 _0) { } /** - * Snoc an element onto the back of this HList. + * Snoc an element onto the back of this {@link Tuple3}. * * @param _4 the new last element - * @return the updated HList + * @param <_4> the new last element type + * @return the new {@link Tuple4} */ public <_4> Tuple4<_1, _2, _3, _4> snoc(_4 _4) { return tuple(_1, _2, _3, _4); 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 f8b630aa5..ebd946548 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 @@ -46,9 +46,9 @@ public class Tuple4<_1, _2, _3, _4> extends HCons<_1, Tuple3<_2, _3, _4>> implem Tuple4(_1 _1, Tuple3<_2, _3, _4> tail) { super(_1, tail); this._1 = _1; - _2 = tail._1(); - _3 = tail._2(); - _4 = tail._3(); + _2 = tail._1(); + _3 = tail._2(); + _4 = tail._3(); } /** @@ -60,10 +60,11 @@ public <_0> Tuple5<_0, _1, _2, _3, _4> cons(_0 _0) { } /** - * Snoc an element onto the back of this HList. + * Snoc an element onto the back of this {@link Tuple4}. * * @param _5 the new last element - * @return the updated HList + * @param <_5> the new last element type + * @return the new {@link Tuple5} */ public <_5> Tuple5<_1, _2, _3, _4, _5> snoc(_5 _5) { return tuple(_1, _2, _3, _4, _5); 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 e7a2c7877..869a41f97 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 @@ -48,10 +48,10 @@ public class Tuple5<_1, _2, _3, _4, _5> extends HCons<_1, Tuple4<_2, _3, _4, _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(); + _2 = tail._1(); + _3 = tail._2(); + _4 = tail._3(); + _5 = tail._4(); } /** @@ -63,10 +63,11 @@ public <_0> Tuple6<_0, _1, _2, _3, _4, _5> cons(_0 _0) { } /** - * Snoc an element onto the back of this HList. + * Snoc an element onto the back of this {@link Tuple5}. * * @param _6 the new last element - * @return the updated HList + * @param <_6> the new last element type + * @return the new {@link Tuple6} */ public <_6> Tuple6<_1, _2, _3, _4, _5, _6> snoc(_6 _6) { return tuple(_1, _2, _3, _4, _5, _6); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index ca65c7793..72bbac9ba 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -51,11 +51,11 @@ public class Tuple6<_1, _2, _3, _4, _5, _6> extends HCons<_1, Tuple5<_2, _3, _4, Tuple6(_1 _1, Tuple5<_2, _3, _4, _5, _6> tail) { super(_1, tail); this._1 = _1; - _2 = tail._1(); - _3 = tail._2(); - _4 = tail._3(); - _5 = tail._4(); - _6 = tail._5(); + _2 = tail._1(); + _3 = tail._2(); + _4 = tail._3(); + _5 = tail._4(); + _6 = tail._5(); } /** @@ -67,10 +67,11 @@ public <_0> Tuple7<_0, _1, _2, _3, _4, _5, _6> cons(_0 _0) { } /** - * Snoc an element onto the back of this HList. + * Snoc an element onto the back of this {@link Tuple6}. * * @param _7 the new last element - * @return the updated HList + * @param <_7> the new last element type + * @return the new {@link Tuple7} */ public <_7> Tuple7<_1, _2, _3, _4, _5, _6, _7> snoc(_7 _7) { return tuple(_1, _2, _3, _4, _5, _6, _7); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index 61f4edf63..3a2f027b7 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -54,12 +54,12 @@ public class Tuple7<_1, _2, _3, _4, _5, _6, _7> extends HCons<_1, Tuple6<_2, _3, Tuple7(_1 _1, Tuple6<_2, _3, _4, _5, _6, _7> tail) { super(_1, tail); this._1 = _1; - _2 = tail._1(); - _3 = tail._2(); - _4 = tail._3(); - _5 = tail._4(); - _6 = tail._5(); - _7 = tail._6(); + _2 = tail._1(); + _3 = tail._2(); + _4 = tail._3(); + _5 = tail._4(); + _6 = tail._5(); + _7 = tail._6(); } /** @@ -71,10 +71,11 @@ public <_0> Tuple8<_0, _1, _2, _3, _4, _5, _6, _7> cons(_0 _0) { } /** - * Snoc an element onto the back of this HList. + * Snoc an element onto the back of this {@link Tuple7}. * * @param _8 the new last element - * @return the updated HList + * @param <_8> the new last element type + * @return the new {@link Tuple8} */ public <_8> Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> snoc(_8 _8) { return tuple(_1, _2, _3, _4, _5, _6, _7, _8); diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index fd6f3d8d0..c97cea46d 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -57,13 +57,13 @@ public class Tuple8<_1, _2, _3, _4, _5, _6, _7, _8> extends HCons<_1, Tuple7<_2, Tuple8(_1 _1, Tuple7<_2, _3, _4, _5, _6, _7, _8> tail) { super(_1, tail); this._1 = _1; - _2 = tail._1(); - _3 = tail._2(); - _4 = tail._3(); - _5 = tail._4(); - _6 = tail._5(); - _7 = tail._6(); - _8 = tail._7(); + _2 = tail._1(); + _3 = tail._2(); + _4 = tail._3(); + _5 = tail._4(); + _6 = tail._5(); + _7 = tail._6(); + _8 = tail._7(); } /** @@ -75,10 +75,11 @@ public <_0> HCons<_0, Tuple8<_1, _2, _3, _4, _5, _6, _7, _8>> cons(_0 _0) { } /** - * Snoc an element onto the back of this HList. + * Snoc an element onto the back of this {@link Tuple8}. * * @param _9 the new last element - * @return the updated HList + * @param <_9> the new last element type + * @return the new {@link HCons consed} {@link Tuple8} */ public <_9> HCons<_1, Tuple8<_2, _3, _4, _5, _6, _7, _8, _9>> snoc(_9 _9) { return singletonHList(_9).cons(_8).cons(_7).cons(_6).cons(_5).cons(_4).cons(_3).cons(_2).cons(_1); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java index 09e9e44d0..3e3513a3a 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/HListTest.java @@ -2,9 +2,15 @@ import org.junit.Test; -import static com.jnape.palatable.lambda.adt.hlist.HList.*; +import static com.jnape.palatable.lambda.adt.hlist.HList.cons; +import static com.jnape.palatable.lambda.adt.hlist.HList.nil; +import static com.jnape.palatable.lambda.adt.hlist.HList.singletonHList; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; public class HListTest { @@ -48,16 +54,15 @@ public void nilReusesInstance() { } @Test - @SuppressWarnings({"EqualsWithItself", "EqualsBetweenInconvertibleTypes"}) public void equality() { - assertTrue(nil().equals(nil())); - assertTrue(cons(1, nil()).equals(cons(1, nil()))); + assertEquals(nil(), nil()); + assertEquals(cons(1, nil()), cons(1, nil())); - assertFalse(cons(1, nil()).equals(nil())); - assertFalse(nil().equals(cons(1, nil()))); + assertNotEquals(cons(1, nil()), nil()); + assertNotEquals(nil(), cons(1, nil())); - assertFalse(cons(1, cons(2, nil())).equals(cons(1, nil()))); - assertFalse(cons(1, nil()).equals(cons(1, cons(2, nil())))); + assertNotEquals(cons(1, cons(2, nil())), cons(1, nil())); + assertNotEquals(cons(1, nil()), cons(1, cons(2, nil()))); } @Test @@ -68,10 +73,4 @@ public void hashCodeUsesDecentDistribution() { assertNotEquals(nil().cons(1).hashCode(), nil().cons(2).hashCode()); assertNotEquals(nil().cons(1).cons(2).hashCode(), nil().cons(1).cons(3).hashCode()); } - - @Test - public void snoc() { - SingletonHList tuple = nil().snoc((float) 4.0); - assertEquals(4.0, tuple.head(), 0.01); - } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java index 6d7d8c0b2..7a577f2ce 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java @@ -47,6 +47,11 @@ public void cons() { assertEquals(new Tuple2<>("0", singletonHList), singletonHList.cons("0")); } + @Test + public void snoc() { + assertEquals(tuple((byte) 127, 'x'), singletonHList((byte) 127).snoc('x')); + } + @Test public void intoAppliesHeadToFn() { assertEquals("FOO", singletonHList("foo").into(String::toUpperCase)); @@ -57,10 +62,4 @@ public void staticPure() { SingletonHList singletonHList = pureSingletonHList().apply(1); assertEquals(singletonHList(1), singletonHList); } - - @Test - public void snoc() { - Tuple2 tuple = singletonHList((byte) 127).snoc('x'); - assertEquals(tuple((byte) 127, 'x'), tuple); - } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index ce28b964b..31dc2f285 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -68,6 +68,11 @@ public void cons() { assertEquals(new Tuple3<>(0, tuple2), tuple2.cons(0)); } + @Test + public void snoc() { + assertEquals(tuple(Long.MAX_VALUE, 123, "hi"), tuple(Long.MAX_VALUE, 123).snoc("hi")); + } + @Test public void accessors() { assertEquals((Integer) 1, tuple2._1()); @@ -143,10 +148,4 @@ public void staticPure() { Tuple2 tuple = pureTuple(1).apply("two"); assertEquals(tuple(1, "two"), tuple); } - - @Test - public void snoc() { - Tuple3 tuple = tuple(Long.MAX_VALUE, 123).snoc("hi"); - assertEquals(tuple(Long.MAX_VALUE, 123, "hi"), tuple); - } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java index aa25c3e59..55842ee8b 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java @@ -13,8 +13,6 @@ import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; -import java.time.Duration; - 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; @@ -65,6 +63,12 @@ public void cons() { assertEquals(new Tuple4<>(0, tuple3), tuple3.cons(0)); } + @Test + public void snoc() { + assertEquals(tuple("qux", Long.MIN_VALUE, 7, ofSeconds(13)), + tuple("qux", Long.MIN_VALUE, 7).snoc(ofSeconds(13))); + } + @Test public void accessors() { assertEquals((Integer) 1, tuple3._1()); @@ -122,10 +126,4 @@ public void staticPure() { Tuple3 tuple = pureTuple(1, "2").apply('3'); assertEquals(tuple(1, "2", '3'), tuple); } - - @Test - public void snoc() { - Tuple4 tuple = tuple("qux", Long.MIN_VALUE, 7).snoc(ofSeconds(13)); - assertEquals(tuple("qux", Long.MIN_VALUE, 7, ofSeconds(13)), tuple); - } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java index a0b27f05e..bb5380891 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java @@ -62,6 +62,11 @@ public void cons() { assertEquals(new Tuple5<>(0, tuple4), tuple4.cons(0)); } + @Test + public void snoc() { + assertEquals(tuple("qux", 7, "foo", 13L, 17), tuple("qux", 7, "foo", 13L).snoc(17)); + } + @Test public void accessors() { assertEquals((Integer) 1, tuple4._1()); @@ -122,10 +127,4 @@ public void staticPure() { Tuple4 tuple = pureTuple(1, "2", '3').apply(true); assertEquals(tuple(1, "2", '3', true), tuple); } - - @Test - public void snoc() { - Tuple5 tuple = tuple("qux", 7, "foo", 13L).snoc(17); - assertEquals(tuple("qux", 7, "foo", 13L, 17), tuple); - } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index ee0d6b7be..f156f9072 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -63,6 +63,11 @@ public void cons() { assertEquals(new HCons<>(0, tuple5), tuple5.cons(0)); } + @Test + public void snoc() { + assertEquals(tuple("a", 5, "b", 7, "c", 11), tuple("a", 5, "b", 7, "c").snoc(11)); + } + @Test public void accessors() { assertEquals((Integer) 1, tuple5._1()); @@ -128,10 +133,4 @@ public void staticPure() { Tuple5 tuple = pureTuple(1, "2", '3', true).apply(5f); assertEquals(tuple(1, "2", '3', true, 5f), tuple); } - - @Test - public void snoc() { - Tuple6 tuple = tuple("a", 5, "b", 7, "c").snoc(11); - assertEquals(tuple("a", 5, "b", 7, "c", 11), tuple); - } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index dd57fde9c..a148ae972 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -64,6 +64,11 @@ public void cons() { assertEquals(new HCons<>(0, tuple6), tuple6.cons(0)); } + @Test + public void snoc() { + assertEquals(tuple(5L, "a", 7, "b", 11, "c", 13), tuple(5L, "a", 7, "b", 11, "c").snoc(13)); + } + @Test public void accessors() { assertEquals((Float) 2.0f, tuple6._1()); @@ -132,10 +137,4 @@ public void staticPure() { Tuple6 tuple = pureTuple(1, "2", '3', true, 5f).apply((byte) 6); assertEquals(tuple(1, "2", '3', true, 5f, (byte) 6), tuple); } - - @Test - public void snoc() { - Tuple7 tuple = tuple(5L, "a", 7, "b", 11, "c").snoc(13); - assertEquals(tuple(5L, "a", 7, "b", 11, "c", 13), tuple); - } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index 14ccb30a6..f1cbb7f3a 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -64,6 +64,11 @@ public void cons() { assertEquals(new HCons<>(0, tuple7), tuple7.cons(0)); } + @Test + public void snoc() { + assertEquals(tuple("b", 7L, "c", 11, "d", 13, "e", 'f'), tuple("b", 7L, "c", 11, "d", 13, "e").snoc('f')); + } + @Test public void accessors() { assertEquals((Byte) (byte) 127, tuple7._1()); @@ -136,10 +141,4 @@ public void staticPure() { pureTuple((byte) 1, (short) 2, 3, 4L, 5F, 6D).apply(true); assertEquals(tuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true), tuple); } - - @Test - public void snoc() { - Tuple8 tuple = tuple("b", 7L, "c", 11, "d", 13, "e").snoc('f'); - assertEquals(tuple("b", 7L, "c", 11, "d", 13, "e", 'f'), tuple); - } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java index 33921079e..dacab1869 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java @@ -69,6 +69,15 @@ public void cons() { assertEquals(new HCons<>(0, tuple8), tuple8.cons(0)); } + @Test + public void snoc() { + LocalDate last = LocalDate.of(2020, 4, 14); + HCons> actual = + tuple("b", 7L, "c", 11, "d", 13, "e", 15L).snoc(last); + assertEquals("b", actual.head()); + assertEquals(actual.tail(), tuple(7L, "c", 11, "d", 13, "e", 15L, last)); + } + @Test public void accessors() { assertEquals((Short) (short) 65535, tuple8._1()); @@ -149,11 +158,4 @@ public void staticPure() { pureTuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true).apply('8'); assertEquals(tuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true, '8'), tuple); } - - @Test - public void snoc() { - HCons> actual = tuple("b", 7L, "c", 11, "d", 13, "e", 15L).snoc(LocalDate.of(2020, 4, 14)); - assertEquals("b", actual.head()); - assertEquals(actual.tail(), tuple(7L, "c", 11, "d", 13, "e", 15L, LocalDate.of(2020, 4, 14))); - } } \ No newline at end of file From 671a61d373a200de6bd0ef0565002bd6d86cdbc2 Mon Sep 17 00:00:00 2001 From: Michael A Date: Mon, 5 Oct 2020 17:46:01 -0500 Subject: [PATCH 312/348] #96 Add WuWei to Community Section --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 312d220fb..b7b46b83f 100644 --- a/README.md +++ b/README.md @@ -746,6 +746,7 @@ There are some open-sourced community projects that depend on _lambda_ for their - [Enhanced Iterables](https://github.com/kschuetz/enhanced-iterables) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) - [Collection Views](https://github.com/kschuetz/collection-views) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) +- [WuWei](https://github.com/nomicflux/WuWei) - Michael Anderson [@nomicflux](https://github.com/nomicflux) - `ST` monad for safe mutability License ------- From 3f23529573f7a2f7f7a11aca3d9d7e720cf2a15b Mon Sep 17 00:00:00 2001 From: Kevin Schuetz Date: Fri, 30 Oct 2020 18:13:44 -0500 Subject: [PATCH 313/348] #98 Add Kraftwerk to Community section --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b7b46b83f..eee42045c 100644 --- a/README.md +++ b/README.md @@ -747,6 +747,7 @@ There are some open-sourced community projects that depend on _lambda_ for their - [Enhanced Iterables](https://github.com/kschuetz/enhanced-iterables) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) - [Collection Views](https://github.com/kschuetz/collection-views) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) - [WuWei](https://github.com/nomicflux/WuWei) - Michael Anderson [@nomicflux](https://github.com/nomicflux) - `ST` monad for safe mutability +- [Kraftwerk](https://github.com/kschuetz/kraftwerk) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) - random data generators and combinators License ------- From d3a049c8df1ba7977b7e50253320499c0094ca8e Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 5 Oct 2020 17:24:39 -0500 Subject: [PATCH 314/348] ReaderT#fmap and StateT#fmap don't unnecessarily rely on pure --- CHANGELOG.md | 1 + .../monad/transformer/builtin/ReaderT.java | 2 +- .../monad/transformer/builtin/StateT.java | 4 ++-- .../monad/transformer/builtin/ReaderTTest.java | 15 +++++++++++++++ .../monad/transformer/builtin/StateTTest.java | 17 +++++++++++++++++ 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e96c8697d..63edf0d5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - `IterateT#unfold` now only computes a single `Pure` for the given input +- `ReaderT#fmap` and `StateT#fmap` avoid unnecessary calls to `pure` ### Added - `$`, function application represented as a higher-order `Fn2` diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index 443470c6e..e7f93a168 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -120,7 +120,7 @@ public ReaderT pure(B b) { */ @Override public ReaderT fmap(Fn1 fn) { - return MonadT.super.fmap(fn).coerce(); + return readerT(r -> runReaderT(r).fmap(fn)); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java index 071ce0dc5..219ad3e03 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateT.java @@ -144,7 +144,7 @@ public StateT pure(B b) { */ @Override public StateT fmap(Fn1 fn) { - return MonadT.super.fmap(fn).coerce(); + return stateT(s -> runStateT(s).fmap(t -> t.biMapL(fn))); } /** @@ -292,7 +292,7 @@ public static , A> StateT stateT( public static > Pure> pureStateT(Pure pureM) { return new Pure>() { @Override - public StateT checkedApply(A a) throws Throwable { + public StateT checkedApply(A a) { return stateT(pureM.>apply(a)); } }; diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java index 6972c9fb6..cbcf1ef8b 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java @@ -2,6 +2,7 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functor.builtin.Identity; import com.jnape.palatable.lambda.io.IO; import com.jnape.palatable.traitor.annotations.TestTraits; @@ -12,6 +13,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Unit.UNIT; @@ -82,4 +84,17 @@ public void composedZip() { .unsafePerformAsyncIO(Executors.newFixedThreadPool(2)) .join(); } + + @Test + public void fmapInteractions() { + AtomicInteger invocations = new AtomicInteger(0); + ReaderT, Integer> readerT = readerT(i -> { + invocations.incrementAndGet(); + return new Identity<>(i); + }); + + Fn1 plusOne = x -> x + 1; + readerT.fmap(plusOne).fmap(plusOne).fmap(plusOne).runReaderT(0); + assertEquals(1, invocations.get()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java index b51888c9d..785165952 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/StateTTest.java @@ -16,15 +16,18 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import static com.jnape.palatable.lambda.adt.Maybe.just; import static com.jnape.palatable.lambda.adt.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.optics.functions.Set.set; import static com.jnape.palatable.lambda.optics.lenses.ListLens.elementAt; import static java.util.Arrays.asList; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; import static testsupport.matchers.StateTMatcher.whenEvaluated; import static testsupport.matchers.StateTMatcher.whenExecuted; import static testsupport.matchers.StateTMatcher.whenRun; @@ -119,4 +122,18 @@ public void staticLift() { assertThat(StateT.liftStateT().apply(new Identity<>(1)), whenRun("foo", new Identity<>(tuple(1, "foo")))); } + + @Test + public void fmapInteractions() { + AtomicInteger invocations = new AtomicInteger(0); + StateT., Integer>gets(x -> { + invocations.incrementAndGet(); + return new Identity<>(x); + }) + .fmap(id()) + .fmap(id()) + .fmap(id()) + .>>runStateT(0); + assertEquals(1, invocations.get()); + } } \ No newline at end of file From cc0cda9b6a6997e6e66a5511e8edb13fd8adde89 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 7 Oct 2020 12:23:33 -0500 Subject: [PATCH 315/348] MaybeT implements MonadError --- CHANGELOG.md | 1 + .../monad/transformer/builtin/MaybeT.java | 24 ++++++++++++++++++- .../monad/transformer/builtin/MaybeTTest.java | 13 +++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63edf0d5d..8cedd4a86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Changed - `IterateT#unfold` now only computes a single `Pure` for the given input - `ReaderT#fmap` and `StateT#fmap` avoid unnecessary calls to `pure` +- `MaybeT` implements `MonadError` ### Added - `$`, function application represented as a higher-order `Fn2` diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java index c2e02fd94..95dcdfd21 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeT.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monad.transformer.builtin; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; import com.jnape.palatable.lambda.functions.Fn1; import com.jnape.palatable.lambda.functions.recursion.RecursiveResult; import com.jnape.palatable.lambda.functions.specialized.Lift; @@ -9,6 +10,7 @@ import com.jnape.palatable.lambda.functor.builtin.Compose; import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monad.Monad; +import com.jnape.palatable.lambda.monad.MonadError; import com.jnape.palatable.lambda.monad.MonadRec; import com.jnape.palatable.lambda.monad.transformer.MonadT; @@ -16,6 +18,8 @@ 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.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.recursion.RecursiveResult.terminate; @@ -26,7 +30,7 @@ * @param the carrier type */ public final class MaybeT, A> implements - MonadT, MaybeT> { + MonadT, MaybeT>, MonadError> { private final MonadRec, M> mma; @@ -67,6 +71,24 @@ public MaybeT or(MaybeT other) { a -> mMaybeA.pure(just(a))))); } + /** + * {@inheritDoc} + */ + @Override + public MaybeT throwError(Unit unit) { + return maybeT(mma.pure(nothing())); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT catchError(Fn1>> recoveryFn) { + return maybeT(mma.flatMap(maybeA -> maybeA.match( + fn0(() -> recoveryFn.apply(UNIT).>coerce().runMaybeT()), + a -> mma.pure(just(a))))); + } + /** * {@inheritDoc} */ diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java index 2c578fbc6..1a81e1c57 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/MaybeTTest.java @@ -22,14 +22,18 @@ import static com.jnape.palatable.lambda.adt.Either.right; 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.Unit.UNIT; import static com.jnape.palatable.lambda.functions.builtin.fn2.GT.gt; import static com.jnape.palatable.lambda.functions.builtin.fn2.LT.lt; import static com.jnape.palatable.lambda.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.lambda.io.IO.io; -import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.*; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.liftMaybeT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.maybeT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.pureMaybeT; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; +import static testsupport.assertion.MonadErrorAssert.assertLaws; @RunWith(Traits.class) public class MaybeTTest { @@ -41,6 +45,13 @@ public class MaybeTTest { maybeT(left("foo"))); } + @Test + public void monadError() { + assertLaws(subjects(maybeT(new Identity<>(nothing())), maybeT(new Identity<>(just(1)))), + UNIT, + e -> maybeT(new Identity<>(just(2)))); + } + @Test public void lazyZip() { assertEquals(maybeT(right(just(2))), From db1cbb7e5be587704421a52ffe5d6de22cc35ad9 Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Thu, 1 Oct 2020 20:17:59 -0500 Subject: [PATCH 316/348] Add init methods to Tuple classes --- CHANGELOG.md | 1 + .../com/jnape/palatable/lambda/adt/hlist/Tuple2.java | 9 +++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple3.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple4.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple5.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple6.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple7.java | 10 ++++++++++ .../com/jnape/palatable/lambda/adt/hlist/Tuple8.java | 10 ++++++++++ .../jnape/palatable/lambda/adt/hlist/Tuple2Test.java | 5 +++++ .../jnape/palatable/lambda/adt/hlist/Tuple3Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple4Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple5Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple6Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple7Test.java | 6 ++++++ .../jnape/palatable/lambda/adt/hlist/Tuple8Test.java | 6 ++++++ 15 files changed, 111 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cedd4a86..4c3add484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `IterateT#unfold` now only computes a single `Pure` for the given input - `ReaderT#fmap` and `StateT#fmap` avoid unnecessary calls to `pure` - `MaybeT` implements `MonadError` +- `Tuple2-8#init`, for populating a `TupleN` with all but the last element ### Added - `$`, function application represented as a higher-order `Fn2` 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 cdf79be12..aafa40b5e 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 @@ -237,6 +237,15 @@ AppTrav extends Applicative> AppTrav traverse( return fn.apply(_2).fmap(_2Prime -> fmap(constantly(_2Prime))).fmap(Applicative::coerce).coerce(); } + /** + * Returns a {@link SingletonHList}<_1> of the first element. + * + * @return The {@link SingletonHList}<_1> + */ + public SingletonHList<_1> init() { + return invert().tail(); + } + /** * Static factory method for creating Tuple2s from {@link java.util.Map.Entry}s. * 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 6fe7710b3..b392ffe38 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 @@ -219,6 +219,16 @@ AppTrav extends Applicative> AppTrav traverse( return fn.apply(_3).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } + /** + * Returns a {@link Tuple2}<_1, _2> of all the elements of this + * {@link Tuple3}<_1, _2, _3> except the last. + * + * @return The {@link Tuple2}<_1, _2> representing all but the last element + */ + public Tuple2<_1, _2> init() { + return rotateR3().tail(); + } + /** * Given a value of type A, produced an instance of this tuple with each slot set to that value. * 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 ebd946548..d8dc42868 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 @@ -246,6 +246,16 @@ AppTrav extends Applicative> AppTrav traverse( return fn.apply(_4).fmap(_4Prime -> fmap(constantly(_4Prime))).fmap(Applicative::coerce).coerce(); } + /** + * Returns a {@link Tuple3}<_1, _2, _3> of all the elements of this + * {@link Tuple4}<_1, _2, _3, _4> except the last. + * + * @return The {@link Tuple3}<_1, _2, _3> representing all but the last element + */ + public Tuple3<_1, _2, _3> init() { + return rotateR4().tail(); + } + /** * Given a value of type A, produced an instance of this tuple with each slot set to that value. * 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 869a41f97..5a6f20cbb 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 @@ -273,6 +273,16 @@ AppTrav extends Applicative> AppTrav traverse( return fn.apply(_5).fmap(_3Prime -> fmap(constantly(_3Prime))).fmap(Applicative::coerce).coerce(); } + /** + * Returns a {@link Tuple4}<_1, _2, _3, _4> of all the elements of this + * {@link Tuple5}<_1, _2, _3, _4, _5> except the last. + * + * @return The {@link Tuple4}<_1, _2, _3, _4> representing all but the last element + */ + public Tuple4<_1, _2, _3, _4> init() { + return rotateR5().tail(); + } + /** * Given a value of type A, produced an instance of this tuple with each slot set to that value. * diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java index 72bbac9ba..1034e3b6b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple6.java @@ -304,6 +304,16 @@ AppTrav extends Applicative> AppTrav traverse( return fn.apply(_6).fmap(_6Prime -> fmap(constantly(_6Prime))).fmap(Applicative::coerce).coerce(); } + /** + * Returns a {@link Tuple5}<_1, _2, _3, _4, _5> of all the elements of this + * {@link Tuple6}<_1, _2, _3, _4, _5, _6> except the last. + * + * @return The {@link Tuple5}<_1, _2, _3, _4, _5> representing all but the last element + */ + public Tuple5<_1, _2, _3, _4, _5> init() { + return rotateR6().tail(); + } + /** * Given a value of type A, produced an instance of this tuple with each slot set to that value. * diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java index 3a2f027b7..cdfe552d6 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple7.java @@ -334,6 +334,16 @@ AppTrav extends Applicative> AppTrav traverse( return fn.apply(_7).fmap(_7Prime -> fmap(constantly(_7Prime))).fmap(Applicative::coerce).coerce(); } + /** + * Returns a {@link Tuple6}<_1, _2, _3, _4, _5, _6> of all the elements of this + * {@link Tuple7}<_1, _2, _3, _4, _5, _6, _7> except the last. + * + * @return The {@link Tuple6}<_1, _2, _3, _4, _5, _6> representing all but the last element + */ + public Tuple6<_1, _2, _3, _4, _5, _6> init() { + return rotateR7().tail(); + } + /** * Given a value of type A, produced an instance of this tuple with each slot set to that value. * diff --git a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java index c97cea46d..079a30611 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/hlist/Tuple8.java @@ -364,6 +364,16 @@ AppTrav extends Applicative> AppTrav traverse( return fn.apply(_8).fmap(_8Prime -> fmap(constantly(_8Prime))).fmap(Applicative::coerce).coerce(); } + /** + * Returns a {@link Tuple7}<_1, _2, _3, _4, _5, _6, _7> of all the elements of this + * {@link Tuple8}<_1, _2, _3, _4, _5, _6, _7, _8> except the last. + * + * @return The {@link Tuple7}<_1, _2, _3, _4, _5, _6, _7> representing all but the last element + */ + public Tuple7<_1, _2, _3, _4, _5, _6, _7> init() { + return rotateR8().tail(); + } + /** * Given a value of type A, produced an instance of this tuple with each slot set to that value. * diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index 31dc2f285..6637386ce 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -63,6 +63,11 @@ public void tail() { assertEquals(new SingletonHList<>(2), tuple2.tail()); } + @Test + public void init() { + assertEquals(new SingletonHList<>(1), tuple2.init()); + } + @Test public void cons() { assertEquals(new Tuple3<>(0, tuple2), tuple2.cons(0)); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java index 55842ee8b..a4cad8198 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java @@ -126,4 +126,10 @@ public void staticPure() { Tuple3 tuple = pureTuple(1, "2").apply('3'); assertEquals(tuple(1, "2", '3'), tuple); } + + @Test + public void init() { + assertEquals(tuple(1, 2), + tuple(1, 2, 3).init()); + } } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java index bb5380891..13d5da838 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java @@ -127,4 +127,10 @@ public void staticPure() { Tuple4 tuple = pureTuple(1, "2", '3').apply(true); assertEquals(tuple(1, "2", '3', true), tuple); } + + @Test + public void init() { + assertEquals(tuple(1, 2, 3), + tuple(1, 2, 3, 4).init()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index f156f9072..7b81a2190 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -133,4 +133,10 @@ public void staticPure() { Tuple5 tuple = pureTuple(1, "2", '3', true).apply(5f); assertEquals(tuple(1, "2", '3', true, 5f), tuple); } + + @Test + public void init() { + assertEquals(tuple(1, 2, 3, 4), + tuple(1, 2, 3, 4, 5).init()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index a148ae972..880eee1e4 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -137,4 +137,10 @@ public void staticPure() { Tuple6 tuple = pureTuple(1, "2", '3', true, 5f).apply((byte) 6); assertEquals(tuple(1, "2", '3', true, 5f, (byte) 6), tuple); } + + @Test + public void init() { + assertEquals(tuple(1, 2, 3, 4, 5), + tuple(1, 2, 3, 4, 5, 6).init()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index f1cbb7f3a..d5b13fd24 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -141,4 +141,10 @@ public void staticPure() { pureTuple((byte) 1, (short) 2, 3, 4L, 5F, 6D).apply(true); assertEquals(tuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true), tuple); } + + @Test + public void init() { + assertEquals(tuple(1, 2, 3, 4, 5, 6), + tuple(1, 2, 3, 4, 5, 6, 7).init()); + } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java index dacab1869..ced5531b5 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java @@ -158,4 +158,10 @@ public void staticPure() { pureTuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true).apply('8'); assertEquals(tuple((byte) 1, (short) 2, 3, 4L, 5F, 6D, true, '8'), tuple); } + + @Test + public void init() { + assertEquals(tuple(1, 2, 3, 4, 5, 6, 7), + tuple(1, 2, 3, 4, 5, 6, 7, 8).init()); + } } \ No newline at end of file From a659fc441b37ae77b9c93f7e5177b35bcd7683ea Mon Sep 17 00:00:00 2001 From: Nate Riffe Date: Fri, 16 Oct 2020 22:37:10 -0500 Subject: [PATCH 317/348] Simplify internal structure of IterateT - Reduce representation of the spine to a single ImmutableQueue containing Choice2s of thunks or realized nodes - Conses and snocs occupy the b "real" side of the coproduct and are pushed to the front or back of the spine, respectively - IterateTs which would have been middles in the old representation are now just another spine to concat onto and are never actually instantiated as IterateTs - Handling of thunks is essentially unchanged - Delegate the iterateT static constructor to suspended and the singleton static constructor to empty with a cons for clarity and concision Fix up formatting - Break the long return type of resume between the Fn1 type arguments - Undo some unintentional reformatting of fromIterator --- .../monad/transformer/builtin/IterateT.java | 90 ++++++------------- 1 file changed, 27 insertions(+), 63 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index 07ea19982..b258cb983 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -68,18 +68,12 @@ public class IterateT, A> implements MonadT, IterateT> { private final Pure pureM; - private final ImmutableQueue> conses; - private final ImmutableQueue>>, M>>, IterateT>> middles; - private final ImmutableQueue> snocs; + private final ImmutableQueue>>, M>>, MonadRec>> spine; private IterateT(Pure pureM, - ImmutableQueue> conses, - ImmutableQueue>>, M>>, IterateT>> middles, - ImmutableQueue> snocs) { - this.pureM = pureM; - this.conses = conses; - this.middles = middles; - this.snocs = snocs; + ImmutableQueue>>, M>>, MonadRec>> spine) { + this.pureM = pureM; + this.spine = spine; } /** @@ -89,7 +83,9 @@ private IterateT(Pure pureM, * @return the embedded {@link Monad} */ public >>, M>> MMTA runIterateT() { - return pureM., MonadRec, M>>apply(this).trampolineM(IterateT::resume).coerce(); + MonadRec>>, M>>, MonadRec>>, M> + mSpine = pureM.apply(spine); + return mSpine.trampolineM(resume(pureM)).coerce(); } /** @@ -99,7 +95,7 @@ public >>, M>> MMTA runIter * @return the cons'ed {@link IterateT} */ public final IterateT cons(MonadRec head) { - return new IterateT<>(pureM, conses.pushFront(head), middles, snocs); + return new IterateT<>(pureM, spine.pushFront(b(head))); } /** @@ -109,7 +105,7 @@ public final IterateT cons(MonadRec head) { * @return the snoc'ed {@link IterateT} */ public final IterateT snoc(MonadRec last) { - return new IterateT<>(pureM, conses, middles, snocs.pushBack(last)); + return new IterateT<>(pureM, spine.pushBack(b(last))); } /** @@ -119,13 +115,7 @@ public final IterateT snoc(MonadRec last) { * @return the concatenated {@link IterateT} */ public IterateT concat(IterateT other) { - return new IterateT<>(pureM, - conses, - middles.pushBack(b(new IterateT<>(pureM, - snocs.concat(other.conses), - other.middles, - other.snocs))), - ImmutableQueue.empty()); + return new IterateT<>(pureM, spine.concat(other.spine)); } /** @@ -289,34 +279,17 @@ public IterateT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } - private MonadRec, Maybe>>>, M> resume() { - return conses.head().match( - __ -> middles.head().match( - ___ -> snocs.head().match( - ____ -> pureM.apply(terminate(nothing())), - ma -> ma.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, - snocs.tail(), - ImmutableQueue.empty(), - ImmutableQueue.empty())))))), - lazyOrStrict -> lazyOrStrict.match( - lazy -> lazy.apply().fmap(maybeRes -> maybeRes.match( - ___ -> recurse(new IterateT<>(pureM, ImmutableQueue.empty(), middles.tail(), snocs)), - into((a, as) -> recurse(new IterateT<>(pureM, - ImmutableQueue.singleton(pureM.apply(a)), - ImmutableQueue.singleton(b(migrateForward(as))), - ImmutableQueue.empty()))) - )), - strict -> pureM.apply(recurse(migrateForward(strict))))), - ma -> ma.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, conses.tail(), middles, snocs)))))); - } - - private IterateT migrateForward(IterateT as) { - if (middles.tail().isEmpty()) { - return new IterateT<>(pureM, conses.concat(as.conses), as.middles, as.snocs.concat(snocs)); - } - - IterateT lasts = new IterateT<>(pureM, as.snocs, middles.tail(), snocs); - return new IterateT<>(pureM, as.conses, as.middles.pushBack(b(lasts)), ImmutableQueue.empty()); + private static , A> + Fn1>>, M>>, MonadRec>>, + MonadRec>>, M>>, MonadRec>>, Maybe>>>, M>> + resume(Pure pureM) { + return spine -> spine.head().match( + ___ -> pureM.apply(terminate(nothing())), + thunkOrReal -> thunkOrReal.match( + thunk -> thunk.apply().fmap(m -> m.match( + ___ -> recurse(spine.tail()), + t -> terminate(just(t.fmap(as -> new IterateT<>(pureM, as.spine.concat(spine.tail()))))))), + real -> real.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, spine.tail()))))))); } private IterateT trampolineM(Fn1, IterateT>> fn, @@ -346,7 +319,7 @@ private IterateT trampolineM(Fn1, A> IterateT empty(Pure pureM) { - return new IterateT<>(pureM, ImmutableQueue.empty(), ImmutableQueue.empty(), ImmutableQueue.empty()); + return new IterateT<>(pureM, ImmutableQueue.empty()); } /** @@ -358,10 +331,7 @@ public static , A> IterateT empty(Pure pureM) * @return the singleton {@link IterateT} */ public static , A> IterateT singleton(MonadRec ma) { - return new IterateT<>(Pure.of(ma), - ImmutableQueue.>empty().pushFront(ma), - ImmutableQueue.empty(), - ImmutableQueue.empty()); + return IterateT.empty(Pure.of(ma)).cons(ma); } /** @@ -374,12 +344,7 @@ public static , A> IterateT singleton(MonadRec, A> IterateT iterateT( MonadRec>>, M> unwrapped) { - return new IterateT<>( - Pure.of(unwrapped), - ImmutableQueue.empty(), - ImmutableQueue.>>, M>>, IterateT>>empty() - .pushFront(a(() -> unwrapped)), - ImmutableQueue.empty()); + return suspended(() -> unwrapped, Pure.of(unwrapped)); } /** @@ -434,11 +399,10 @@ public static , A, B> IterateT unfold( public static , A> IterateT suspended( Fn0>>, M>> thunk, Pure pureM) { return new IterateT<>(pureM, - ImmutableQueue.empty(), ImmutableQueue - .>>, M>>, IterateT>>empty() - .pushFront(a(thunk)), - ImmutableQueue.empty()); + .>>, M>>, MonadRec>>empty() + .pushFront(a(thunk)) + ); } /** From 8e059cc422606a85ad0bf1be3273c1d0edb0ee81 Mon Sep 17 00:00:00 2001 From: Nate Riffe Date: Tue, 10 Nov 2020 13:51:24 -0600 Subject: [PATCH 318/348] Failing test case for IterateT::trampolineM The existing implementation of trampolineM has a bug. The lambda on line 305 does not process `rest` leading to a premature termination of the overall trampoline operation. --- .../lambda/monad/transformer/builtin/IterateTTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java index b74e93835..4ff96ed78 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java @@ -247,4 +247,14 @@ public void staticLift() { ., IterateT, Integer>>apply(new Identity<>(1)) ., Identity>>toCollection(ArrayList::new)); } + + @Test + public void trampolineMRecursesBreadth() { + IterateT, Integer> firstFour = of(new Identity<>(1), new Identity<>(2), new Identity<>(3), new Identity<>(4)); + IterateT, Integer> trampolined = firstFour + .trampolineM(x -> (x % 3 == 0 && (x < 30)) + ? of(new Identity<>(terminate(x + 10)), new Identity<>(recurse(x + 11)), new Identity<>(recurse(x + 12)), new Identity<>(recurse(x + 13))) + : singleton(new Identity<>(terminate(x)))); + assertThat(trampolined, iterates(1, 2, 13, 14, 25, 26, 37, 38, 39, 40, 28, 16, 4)); + } } \ No newline at end of file From 8511223173d43736082c8baba4ce753269026acf Mon Sep 17 00:00:00 2001 From: Nate Riffe Date: Tue, 10 Nov 2020 14:01:17 -0600 Subject: [PATCH 319/348] Simplify and fix IterateT::trampolineM By changing the type of queue from `ImmutableQueue>>` to just `IterateT>`, there is no need to consider the total queue in two dimensions. This simplifies the suspended thunk down to the three fundamental cases that have to be handled: 1) The queue (which is now an `IterateT`) is empty: terminate(nothing()) 2) The first element is a recurse: map it to the concatenation of the processed A and the existing tail 3) The first element is a terminate: emit the node Additionally, the private arity-2 trampoline can be converted to a `withSelf` lambda to put the entire implementation in one place. --- .../monad/transformer/builtin/IterateT.java | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index b258cb983..29196dd5d 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -181,9 +181,19 @@ public > IterateT lift(MonadRec nb) { * {@inheritDoc} */ @Override + @SuppressWarnings("RedundantTypeArguments") public IterateT trampolineM( Fn1, IterateT>> fn) { - return trampolineM(fn, ImmutableQueue.>>empty().pushBack(flatMap(fn))); + return $(withSelf( + (self, queued) -> suspended( + () -> pureM.>, MonadRec>, M>>apply(queued) + .trampolineM(q -> q.runIterateT().>, Maybe>>>>fmap(m -> m.match( + __ -> terminate(nothing()), + into((rr, tail) -> rr.biMap( + a -> fn.apply(a).>>coerce().concat(tail), + b -> just(tuple(b, self.apply(tail)))))))), + pureM)), + flatMap(fn)); } /** @@ -292,24 +302,6 @@ public IterateT discardR(Applicative> appB) { real -> real.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, spine.tail()))))))); } - private IterateT trampolineM(Fn1, IterateT>> fn, - ImmutableQueue>> queued) { - return suspended(() -> { - MonadRec>>, M> pureQueue = pureM.apply(queued); - return pureQueue.trampolineM( - q -> q.head().match( - __ -> pureM.apply(terminate(nothing())), - next -> next.runIterateT().flatMap(maybeMore -> maybeMore.match( - __ -> pureM.apply(terminate(nothing())), - t -> t.into((aOrB, rest) -> aOrB.match( - a -> pureM.apply(recurse(q.pushFront(fn.apply(a).coerce()))), - b -> trampolineM(fn, q.tail().pushFront(rest)) - .cons(pureM.apply(b)) - .runIterateT() - .fmap(RecursiveResult::terminate))))))); - }, pureM); - } - /** * Static factory method for creating an empty {@link IterateT}. * From 7ac280ce806f87b968094ab118c5288dc4945c13 Mon Sep 17 00:00:00 2001 From: Nate Riffe Date: Tue, 10 Nov 2020 14:12:00 -0600 Subject: [PATCH 320/348] Simplify `of` and `suspended` static constructors - `of` can use a singleton as the seed instead of an empty and avoid consing a to as - `suspended` can construct a singleton queue instead of pushing onto an empty queue --- .../lambda/monad/transformer/builtin/IterateT.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index 29196dd5d..f8e155aa1 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -353,9 +353,7 @@ public static , A> IterateT of( MonadRec ma, MonadRec... mas) { @SuppressWarnings("varargs") List> as = asList(mas); - return foldLeft(IterateT::snoc, - empty(Pure.of(ma)), - com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons(ma, as)); + return foldLeft(IterateT::snoc, singleton(ma), as); } /** @@ -390,11 +388,7 @@ public static , A, B> IterateT unfold( */ public static , A> IterateT suspended( Fn0>>, M>> thunk, Pure pureM) { - return new IterateT<>(pureM, - ImmutableQueue - .>>, M>>, MonadRec>>empty() - .pushFront(a(thunk)) - ); + return new IterateT<>(pureM, ImmutableQueue.singleton(a(thunk))); } /** From 9c57a344393b393c13a1f78c07e4f31bac439849 Mon Sep 17 00:00:00 2001 From: Nate Riffe Date: Tue, 10 Nov 2020 14:16:45 -0600 Subject: [PATCH 321/348] Inline resume Add explicit type arguments to the first match in the lambda returned by resume so that resume can be inlined, renaming the `spine` lambda parameter to `tSpine` for disambiguation --- .../monad/transformer/builtin/IterateT.java | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index f8e155aa1..df49e428d 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -85,7 +85,13 @@ private IterateT(Pure pureM, public >>, M>> MMTA runIterateT() { MonadRec>>, M>>, MonadRec>>, M> mSpine = pureM.apply(spine); - return mSpine.trampolineM(resume(pureM)).coerce(); + return mSpine.trampolineM(tSpine -> tSpine.head().>>, M>>, MonadRec>>, Maybe>>>, M>>match( + ___ -> pureM.apply(terminate(nothing())), + thunkOrReal -> thunkOrReal.match( + thunk -> thunk.apply().fmap(m -> m.match( + ___ -> recurse(tSpine.tail()), + t -> terminate(just(t.fmap(as -> new IterateT<>(pureM, as.spine.concat(tSpine.tail()))))))), + real -> real.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, tSpine.tail())))))))).coerce(); } /** @@ -289,19 +295,6 @@ public IterateT discardR(Applicative> appB) { return MonadT.super.discardR(appB).coerce(); } - private static , A> - Fn1>>, M>>, MonadRec>>, - MonadRec>>, M>>, MonadRec>>, Maybe>>>, M>> - resume(Pure pureM) { - return spine -> spine.head().match( - ___ -> pureM.apply(terminate(nothing())), - thunkOrReal -> thunkOrReal.match( - thunk -> thunk.apply().fmap(m -> m.match( - ___ -> recurse(spine.tail()), - t -> terminate(just(t.fmap(as -> new IterateT<>(pureM, as.spine.concat(spine.tail()))))))), - real -> real.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, spine.tail()))))))); - } - /** * Static factory method for creating an empty {@link IterateT}. * From 2cdc1cf0425ffd89c2783483620dbe4473ee75f8 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 11 Nov 2020 14:23:08 -0600 Subject: [PATCH 322/348] Updating CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c3add484..d75c39359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). - `Fn1#withSelf`, a static method for constructing a self-referencing `Fn1` - `HNil/SingletonHList/TupleX#snoc`, a method to add a new last element (append to a tuple) +### Fixed +- `IterateT#trampolineM` now yields and stages all recursive result values, rather + than prematurely terminating on the first termination result + ## [5.2.0] - 2020-02-12 ### Changed From cda383d4aa525e95ce3e86e293a7e4517d1456b7 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 27 Nov 2020 12:38:52 -0600 Subject: [PATCH 323/348] IterateT#flatMap is now stack-safe regardless of how many consecutive empty `IterateT`s are returned --- CHANGELOG.md | 2 + .../monad/transformer/builtin/IterateT.java | 17 +++-- .../transformer/builtin/IterateTTest.java | 72 ++++++++++++++++--- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d75c39359..1a1bf3b6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Fixed - `IterateT#trampolineM` now yields and stages all recursive result values, rather than prematurely terminating on the first termination result +- `IterateT#flatMap` is now stack-safe regardless of how many consecutive empty `IterateT`s + are returned and regardless of whether the monad is strict or lazy or internally trampolined ## [5.2.0] - 2020-02-12 diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index df49e428d..d651795b5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -29,6 +29,7 @@ import static com.jnape.palatable.lambda.adt.choice.Choice2.a; import static com.jnape.palatable.lambda.adt.choice.Choice2.b; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.Fn0.fn0; import static com.jnape.palatable.lambda.functions.Fn1.withSelf; import static com.jnape.palatable.lambda.functions.builtin.fn2.$.$; import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into; @@ -65,7 +66,7 @@ * @param the element type */ public class IterateT, A> implements - MonadT, IterateT> { + MonadT, IterateT> { private final Pure pureM; private final ImmutableQueue>>, M>>, MonadRec>> spine; @@ -208,11 +209,15 @@ public IterateT trampolineM( @Override public IterateT flatMap(Fn1>> f) { return suspended(() -> maybeT(runIterateT()) - .flatMap(into((a, as) -> maybeT(f.apply(a) - .>coerce() - .concat(as.flatMap(f)) - .runIterateT()))) - .runMaybeT(), pureM); + .trampolineM(into((a, as) -> maybeT( + f.apply(a).>coerce().runIterateT() + .flatMap(maybePair -> maybePair.match( + fn0(() -> as.runIterateT() + .fmap(maybeResult -> maybeResult.fmap(RecursiveResult::recurse))), + t -> pureM.apply(just(terminate(t.fmap(mb -> mb.concat(as.flatMap(f)))))) + ))))) + .runMaybeT(), + pureM); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java index 4ff96ed78..a0e974d43 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java @@ -8,31 +8,47 @@ import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.functor.builtin.Writer; import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monoid.Monoid; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.framework.Subjects; import com.jnape.palatable.traitor.runners.Traits; import org.junit.Test; import org.junit.runner.RunWith; -import testsupport.traits.*; +import testsupport.traits.ApplicativeLaws; +import testsupport.traits.Equivalence; +import testsupport.traits.FunctorLaws; +import testsupport.traits.MonadLaws; +import testsupport.traits.MonadRecLaws; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; 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.Unit.UNIT; import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn2.LTE.lte; import static com.jnape.palatable.lambda.functions.builtin.fn3.Times.times; 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.functor.builtin.Identity.pureIdentity; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; -import static com.jnape.palatable.lambda.functor.builtin.Writer.*; +import static com.jnape.palatable.lambda.functor.builtin.Writer.listen; +import static com.jnape.palatable.lambda.functor.builtin.Writer.pureWriter; +import static com.jnape.palatable.lambda.functor.builtin.Writer.tell; +import static com.jnape.palatable.lambda.functor.builtin.Writer.writer; import static com.jnape.palatable.lambda.io.IO.io; -import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.*; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.empty; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.iterateT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.liftIterateT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.of; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.pureIterateT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.singleton; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.unfold; import static com.jnape.palatable.lambda.monoid.builtin.AddAll.addAll; import static com.jnape.palatable.lambda.monoid.builtin.Join.join; import static com.jnape.palatable.traitor.framework.Subjects.subjects; @@ -44,7 +60,9 @@ import static org.junit.Assert.assertThat; import static testsupport.Constants.STACK_EXPLODING_NUMBER; import static testsupport.matchers.IOMatcher.yieldsValue; -import static testsupport.matchers.IterateTMatcher.*; +import static testsupport.matchers.IterateTMatcher.isEmpty; +import static testsupport.matchers.IterateTMatcher.iterates; +import static testsupport.matchers.IterateTMatcher.iteratesAll; import static testsupport.traits.Equivalence.equivalence; @RunWith(Traits.class) @@ -236,16 +254,16 @@ public void concatIsStackSafe() { public void staticPure() { assertEquals(new Identity<>(singletonList(1)), pureIterateT(pureIdentity()) - ., Integer>>apply(1) - ., Identity>>toCollection(ArrayList::new)); + ., Integer>>apply(1) + ., Identity>>toCollection(ArrayList::new)); } @Test public void staticLift() { assertEquals(new Identity<>(singletonList(1)), liftIterateT() - ., IterateT, Integer>>apply(new Identity<>(1)) - ., Identity>>toCollection(ArrayList::new)); + ., IterateT, Integer>>apply(new Identity<>(1)) + ., Identity>>toCollection(ArrayList::new)); } @Test @@ -257,4 +275,42 @@ public void trampolineMRecursesBreadth() { : singleton(new Identity<>(terminate(x)))); assertThat(trampolined, iterates(1, 2, 13, 14, 25, 26, 37, 38, 39, 40, 28, 16, 4)); } + + @Test + public void flatMapToEmptyStackSafety() { + assertEquals(new Identity<>(UNIT), + unfold(x -> new Identity<>(x <= STACK_EXPLODING_NUMBER ? just(tuple(x, x + 1)) : nothing()), + new Identity<>(1)) + .flatMap(constantly(iterateT(new Identity<>(nothing())))) + .forEach(constantly(new Identity<>(UNIT)))); + + assertEquals((Integer) 1_250_025_000, + unfold(x -> listen(x <= STACK_EXPLODING_NUMBER ? just(tuple(x, x + 1)) : nothing()), + Writer.listen(1)) + .flatMap(x -> iterateT(writer(tuple(nothing(), x)))) + .>forEach(constantly(listen(UNIT))) + .runWriter(Monoid.monoid(Integer::sum, 0)) + ._2()); + } + + @Test + public void flatMapCostsNoMoreEffortThanRequiredToYieldFirstValue() { + AtomicInteger flatMapCost = new AtomicInteger(0); + AtomicInteger unfoldCost = new AtomicInteger(0); + assertEquals(just(1), + unfold(x -> { + unfoldCost.incrementAndGet(); + return new Identity<>(x <= 10 ? just(tuple(x, x + 1)) : nothing()); + }, + new Identity<>(1)) + .flatMap(x -> { + flatMapCost.incrementAndGet(); + return singleton(new Identity<>(x)); + }) + ., Integer>>>>>runIterateT() + .runIdentity() + .fmap(Tuple2::_1)); + assertEquals(1, flatMapCost.get()); + assertEquals(1, unfoldCost.get()); + } } \ No newline at end of file From d02c0bc9972b188f8f140c0c7dde0fe7ce9a737a Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 27 Nov 2020 17:13:13 -0600 Subject: [PATCH 324/348] [maven-release-plugin] prepare release lambda-5.3.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bda3d7caf..820393917 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.2.1-SNAPSHOT + 5.3.0 jar Lambda From 256d3302a9b8a6eb6e5eee8cba2ab1ecf828ebd1 Mon Sep 17 00:00:00 2001 From: jnape Date: Fri, 27 Nov 2020 17:13:20 -0600 Subject: [PATCH 325/348] [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 820393917..cc4cfc72d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.3.0 + 5.3.1-SNAPSHOT jar Lambda From ee4371e8626c703458b47cba57784d10922ffdbe Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 7 Dec 2020 10:20:23 -0600 Subject: [PATCH 326/348] Updating CHANGELOG.md --- CHANGELOG.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a1bf3b6b..9c95ef614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,16 +5,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] +There are currently no unreleased changes. + +## [5.3.0] - 2020-12-07 + ### Changed - `IterateT#unfold` now only computes a single `Pure` for the given input - `ReaderT#fmap` and `StateT#fmap` avoid unnecessary calls to `pure` - `MaybeT` implements `MonadError` -- `Tuple2-8#init`, for populating a `TupleN` with all but the last element ### Added - `$`, function application represented as a higher-order `Fn2` -- `Fn1#withSelf`, a static method for constructing a self-referencing `Fn1` +- `Fn1#withSelf`, a static method for constructing a self-referencing `Fn1` - `HNil/SingletonHList/TupleX#snoc`, a method to add a new last element (append to a tuple) +- `Tuple2-8#init`, for populating a `TupleN` with all but the last element ### Fixed - `IterateT#trampolineM` now yields and stages all recursive result values, rather @@ -576,7 +580,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-5.2.0...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-5.3.0...HEAD +[5.3.0]: https://github.com/palatable/lambda/compare/lambda-5.2.0...lambda-5.3.0 [5.2.0]: https://github.com/palatable/lambda/compare/lambda-5.1.0...lambda-5.2.0 [5.1.0]: https://github.com/palatable/lambda/compare/lambda-5.0.0...lambda-5.1.0 [5.0.0]: https://github.com/palatable/lambda/compare/lambda-4.0.0...lambda-5.0.0 From 48ae7020641708ef9af7e00ef16a7b38c5742839 Mon Sep 17 00:00:00 2001 From: jnape Date: Mon, 7 Dec 2020 10:21:01 -0600 Subject: [PATCH 327/348] Updating README to reference latest version --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eee42045c..85790b22e 100644 --- a/README.md +++ b/README.md @@ -61,14 +61,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 5.2.0 + 5.3.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '5.2.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '5.3.0' ``` Examples From a472c9f59b4b0825de2fa4b8098acb799cb1437a Mon Sep 17 00:00:00 2001 From: John Napier Date: Wed, 9 Dec 2020 15:00:29 -0600 Subject: [PATCH 328/348] Updating community section of README --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 85790b22e..060d4e9ee 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Functional patterns for Java - [Either](#either) - [Lenses](#lenses) - [Notes](#notes) - - [Community](#community) + - [Ecosystem](#ecosystem) - [License](#license) Background @@ -740,9 +740,18 @@ Wherever possible, _lambda_ maintains interface compatibility with similar, fami Unfortunately, due to Java's type hierarchy and inheritance inconsistencies, this is not always possible. One surprising example of this is how `Fn1` extends `j.u.f.Function`, but `Fn2` does not extend `j.u.f.BiFunction`. This is because `j.u.f.BiFunction` itself does not extend `j.u.f.Function`, but it does define methods that collide with `j.u.f.Function`. For this reason, both `Fn1` and `Fn2` cannot extend their Java counterparts without sacrificing their own inheritance hierarchy. These types of asymmetries are, unfortunately, not uncommon; however, wherever these situations arise, measures are taken to attempt to ease the transition in and out of core Java types (in the case of `Fn2`, a supplemental `#toBiFunction` method is added). I do not take these inconveniences for granted, and I'm regularly looking for ways to minimize the negative impact of this as much as possible. Suggestions and use cases that highlight particular pain points here are particularly appreciated. -Community +Ecosystem ----- -There are some open-sourced community projects that depend on _lambda_ for their own functionality: these projects are listed below (note that these projects are _not_ affiliated with lambda, and have their own maintainers). If you use _lambda_ in your own open-sourced project, feel free to create an issue and I'll be happy to review the project and add it to this section! + +### Official extension libraries: + +These are officially supported libraries that extend lambda's core functionality and are developed under the same governance and processes as lambda. + +- [Shōki](https://github.com/palatable/shoki) - Purely functional, persistent data structures for the JVM + +### Third-party community libraries: + +These are open-sourced community projects that rely on _lambda_ for significant functionality, but are not necessarily affiliated with lambda and have their own separate maintainers. If you use _lambda_ in your own open-sourced project, feel free to create an issue and I'll be happy to review the project and add it to this section! - [Enhanced Iterables](https://github.com/kschuetz/enhanced-iterables) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) - [Collection Views](https://github.com/kschuetz/collection-views) - Kevin Schuetz [@kschuetz](https://github.com/kschuetz) From 86743e0978cdf200a5f7f009d9975c43729d8eef Mon Sep 17 00:00:00 2001 From: Nate Riffe Date: Sun, 6 Dec 2020 09:40:04 -0600 Subject: [PATCH 329/348] Loosen EitherMatcher types, add static constructors Add isRight() and isLeft() matcher constructors to EitherMatcher. To implement these using the anything() core matcher as the inner matcher, the type signature in isRightThat(..) and isLeftThat(..) has to be loosened since this and some other core matchers are not strictly typed with parameterized types. --- .../testsupport/matchers/EitherMatcher.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/test/java/testsupport/matchers/EitherMatcher.java b/src/test/java/testsupport/matchers/EitherMatcher.java index 748d01be2..2023a22b2 100644 --- a/src/test/java/testsupport/matchers/EitherMatcher.java +++ b/src/test/java/testsupport/matchers/EitherMatcher.java @@ -9,11 +9,12 @@ import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.io.IO.io; +import static org.hamcrest.CoreMatchers.anything; public final class EitherMatcher extends TypeSafeMatcher> { - private final Either, Matcher> matcher; + private final Either, Matcher> matcher; - private EitherMatcher(Either, Matcher> matcher) { + private EitherMatcher(Either, Matcher> matcher) { this.matcher = matcher; } @@ -44,11 +45,19 @@ public void describeTo(Description description) { .unsafePerformIO(); } - public static EitherMatcher isLeftThat(Matcher lMatcher) { + public static EitherMatcher isLeftThat(Matcher lMatcher) { return new EitherMatcher<>(left(lMatcher)); } - public static EitherMatcher isRightThat(Matcher rMatcher) { + public static EitherMatcher isLeft() { + return isLeftThat(anything()); + } + + public static EitherMatcher isRightThat(Matcher rMatcher) { return new EitherMatcher<>(right(rMatcher)); } + + public static EitherMatcher isRight() { + return isRightThat(anything()); + } } From 777949bc0f332d1966d76507f8e4a09d9072a7a3 Mon Sep 17 00:00:00 2001 From: jnape Date: Wed, 23 Dec 2020 18:29:46 -0600 Subject: [PATCH 330/348] Adding IterateT#runStep for supporting interleaving semantics --- CHANGELOG.md | 5 ++- .../monad/transformer/builtin/IterateT.java | 39 ++++++++++++++----- .../transformer/builtin/IterateTTest.java | 36 +++++++++++++++++ 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c95ef614..13f3971a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] -There are currently no unreleased changes. +### Added + +- `IterateT#runStep`, a method used to run a single step of an IterateT without the contractual + guarantee of emitting a value or reaching the end ## [5.3.0] - 2020-12-07 diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java index d651795b5..cb719060b 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateT.java @@ -65,8 +65,7 @@ * @param the effect type * @param the element type */ -public class IterateT, A> implements - MonadT, IterateT> { +public class IterateT, A> implements MonadT, IterateT> { private final Pure pureM; private final ImmutableQueue>>, M>>, MonadRec>> spine; @@ -84,15 +83,35 @@ private IterateT(Pure pureM, * @return the embedded {@link Monad} */ public >>, M>> MMTA runIterateT() { - MonadRec>>, M>>, MonadRec>>, M> - mSpine = pureM.apply(spine); - return mSpine.trampolineM(tSpine -> tSpine.head().>>, M>>, MonadRec>>, Maybe>>>, M>>match( - ___ -> pureM.apply(terminate(nothing())), + return pureM., MonadRec, M>>apply(this) + .>>>trampolineM(iterateT -> iterateT.runStep() + .fmap(maybeMore -> maybeMore.match( + fn0(() -> terminate(nothing())), + t -> t.into((Maybe maybeA, IterateT as) -> maybeA.match( + fn0(() -> recurse(as)), + a -> terminate(just(tuple(a, as)))))))) + .coerce(); + } + + /** + * Run a single step of this {@link IterateT}, where a step is the smallest amount of work that could possibly be + * productive in advancing through the {@link IterateT}. Useful for implementing interleaving algorithms that + * require {@link IterateT IterateTs} to yield, emit, or terminate as soon as possible, regardless of whether the + * next element is readily available. + * + * @param the witnessed target type of the step + * @return the step + */ + public , IterateT>>, M>> MStep runStep() { + return spine.head().match( + fn0(() -> pureM., IterateT>>, MStep>apply(nothing())), thunkOrReal -> thunkOrReal.match( - thunk -> thunk.apply().fmap(m -> m.match( - ___ -> recurse(tSpine.tail()), - t -> terminate(just(t.fmap(as -> new IterateT<>(pureM, as.spine.concat(tSpine.tail()))))))), - real -> real.fmap(a -> terminate(just(tuple(a, new IterateT<>(pureM, tSpine.tail())))))))).coerce(); + thunk -> thunk.apply()., IterateT>>>fmap(m -> m.match( + fn0(() -> just(tuple(nothing(), new IterateT<>(pureM, spine.tail())))), + t -> just(t.biMap(Maybe::just, + as -> new IterateT<>(pureM, as.spine.concat(spine.tail())))))) + .coerce(), + ma -> ma.fmap(a -> just(tuple(just(a), new IterateT<>(pureM, spine.tail())))).coerce())); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java index a0e974d43..7c2997ca6 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/IterateTTest.java @@ -48,6 +48,7 @@ import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.of; import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.pureIterateT; import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.singleton; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.suspended; import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.unfold; import static com.jnape.palatable.lambda.monoid.builtin.AddAll.addAll; import static com.jnape.palatable.lambda.monoid.builtin.Join.join; @@ -313,4 +314,39 @@ public void flatMapCostsNoMoreEffortThanRequiredToYieldFirstValue() { assertEquals(1, flatMapCost.get()); assertEquals(1, unfoldCost.get()); } + + @Test + public void runStep() { + assertEquals(new Identity<>(nothing()), + IterateT., Integer>empty(pureIdentity()) + ., IterateT, Integer>>>>>runStep()); + + Tuple2, IterateT, Integer>> singletonStep = + singleton(new Identity<>(1)) + ., IterateT, Integer>>>>>runStep() + .runIdentity() + .orElseThrow(AssertionError::new); + assertEquals(just(1), singletonStep._1()); + assertThat(singletonStep._2(), isEmpty()); + + Tuple2, IterateT, Integer>> emptySuspendedStep = + IterateT., Integer>suspended(() -> new Identity<>(nothing()), + pureIdentity()) + ., IterateT, Integer>>>>>runStep() + .runIdentity() + .orElseThrow(AssertionError::new); + + assertEquals(nothing(), emptySuspendedStep._1()); + assertThat(emptySuspendedStep._2(), isEmpty()); + + Tuple2, IterateT, Integer>> nonEmptySuspendedStep = + suspended(() -> new Identity<>(just(tuple(1, empty(pureIdentity())))), + pureIdentity()) + ., IterateT, Integer>>>>>runStep() + .runIdentity() + .orElseThrow(AssertionError::new); + + assertEquals(just(1), nonEmptySuspendedStep._1()); + assertThat(nonEmptySuspendedStep._2(), isEmpty()); + } } \ No newline at end of file From 7af1b9c478ede6c755045b75e7d342572d73d82f Mon Sep 17 00:00:00 2001 From: Armando Cordova <18663098+corlaez@users.noreply.github.com> Date: Mon, 15 Mar 2021 16:52:59 -0400 Subject: [PATCH 331/348] Absent folds short-circuit (#116) --- .../lambda/semigroup/builtin/Absent.java | 48 ++++++++++- .../lambda/semigroup/builtin/AbsentTest.java | 80 ++++++++++++++++++- 2 files changed, 120 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java index a692eac77..68162ad74 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java @@ -2,11 +2,21 @@ import com.jnape.palatable.lambda.adt.Maybe; import com.jnape.palatable.lambda.functions.Fn1; -import com.jnape.palatable.lambda.functions.builtin.fn3.LiftA2; +import com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight; import com.jnape.palatable.lambda.functions.specialized.SemigroupFactory; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import com.jnape.palatable.lambda.monoid.builtin.Present; import com.jnape.palatable.lambda.semigroup.Semigroup; +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.functions.builtin.fn2.Into.into; +import static com.jnape.palatable.lambda.functions.builtin.fn3.LiftA2.liftA2; +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 com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; + /** * A {@link Semigroup} instance formed by {@link Maybe}<A> and a semigroup over A. The * application to two {@link Maybe} values is absence-biased, such that for a given {@link Maybe} x @@ -32,7 +42,7 @@ private Absent() { @Override public Semigroup> checkedApply(Semigroup aSemigroup) { - return LiftA2., Maybe>liftA2(aSemigroup)::apply; + return shortCircuitSemigroup(aSemigroup); } @SuppressWarnings("unchecked") @@ -40,8 +50,8 @@ public static Absent absent() { return (Absent) INSTANCE; } - public static Semigroup> absent(Semigroup semigroup) { - return Absent.absent().apply(semigroup); + public static Semigroup> absent(Semigroup aSemigroup) { + return shortCircuitSemigroup(aSemigroup); } public static Fn1, Maybe> absent(Semigroup aSemigroup, Maybe x) { @@ -51,4 +61,34 @@ public static Fn1, Maybe> absent(Semigroup aSemigroup, Maybe< public static Maybe absent(Semigroup semigroup, Maybe x, Maybe y) { return absent(semigroup, x).apply(y); } + + private static Semigroup> shortCircuitSemigroup(Semigroup aSemigroup) { + return new Semigroup>() { + @Override + public Maybe checkedApply(Maybe maybeX, Maybe maybeY) { + return liftA2(aSemigroup, maybeX, maybeY); + } + + @Override + public Maybe foldLeft(Maybe acc, Iterable> maybes) { + return trampoline( + into((res, it) -> res.equals(nothing()) + ? terminate(res) + : recurse(tuple(liftA2(aSemigroup, res, it.next()), it))), + tuple(acc, maybes.iterator())); + } + + @Override + public Lazy> foldRight(Maybe accumulation, Iterable> as) { + boolean shouldShortCircuit = accumulation == nothing(); + if (shouldShortCircuit) + return lazy(accumulation); + return FoldRight.foldRight( + (maybeX, acc) -> maybeX.lazyZip(acc.fmap(maybeY -> maybeY.fmap(aSemigroup.flip()))), + lazy(accumulation), + as + ); + } + }; + } } diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java index 5ef25395e..5ab7b53f6 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java @@ -1,10 +1,17 @@ package com.jnape.palatable.lambda.semigroup.builtin; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.Unit; +import com.jnape.palatable.lambda.functions.builtin.fn1.Constantly; import com.jnape.palatable.lambda.semigroup.Semigroup; import org.junit.Test; +import java.util.Arrays; + 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.Unit.UNIT; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Repeat.repeat; import static com.jnape.palatable.lambda.semigroup.builtin.Absent.absent; import static org.junit.Assert.assertEquals; @@ -12,12 +19,77 @@ public class AbsentTest { @Test public void semigroup() { + Semigroup addition = Integer::sum; + + assertEquals(just(3), absent(addition, just(1), just(2))); + assertEquals(nothing(), absent(addition, nothing(), just(1))); + assertEquals(nothing(), absent(addition, just(1), nothing())); + assertEquals(nothing(), absent(addition, nothing(), nothing())); + } + + @Test + public void foldRight() { + Absent absent = absent(); + Semigroup addition = Integer::sum; + + assertEquals(just(3), absent.apply(addition).foldRight(just(0), Arrays.asList(just(1), just(2))).value()); + assertEquals(nothing(), absent.apply(addition).foldRight(just(0), Arrays.asList(nothing(), just(1))).value()); + assertEquals(nothing(), absent.apply(addition).foldRight(just(0), Arrays.asList(just(1), nothing())).value()); + assertEquals(nothing(), absent.apply(addition).foldRight(just(0), Arrays.asList(nothing(), nothing())).value()); + } + + @Test + public void foldLeft() { Absent absent = absent(); Semigroup addition = Integer::sum; - assertEquals(just(3), absent.apply(addition, just(1), just(2))); - assertEquals(nothing(), absent.apply(addition, nothing(), just(1))); - assertEquals(nothing(), absent.apply(addition, just(1), nothing())); - assertEquals(nothing(), absent.apply(addition, nothing(), nothing())); + assertEquals(just(3), absent.apply(addition).foldLeft(just(0), Arrays.asList(just(1), just(2)))); + assertEquals(nothing(), absent.apply(addition).foldLeft(just(0), Arrays.asList(nothing(), just(1)))); + assertEquals(nothing(), absent.apply(addition).foldLeft(just(0), Arrays.asList(just(1), nothing()))); + assertEquals(nothing(), absent.apply(addition).foldLeft(just(0), Arrays.asList(nothing(), nothing()))); + } + + @Test(timeout = 200) + public void foldRightShortCircuit() { + Maybe result = Absent.absent(Constantly::constantly) + .foldRight(just(UNIT), repeat(nothing())).value(); + assertEquals(nothing(), result); + + result = Absent.absent(Constantly::constantly) + .foldRight(nothing(), repeat(just(UNIT))).value(); + assertEquals(nothing(), result); + } + + @Test(timeout = 200) + public void foldLeftShortCircuit() { + Maybe result = Absent.absent(Constantly::constantly) + .foldLeft(just(UNIT), repeat(nothing())); + assertEquals(nothing(), result); + + result = Absent.absent(Constantly::constantly) + .foldLeft(nothing(), repeat(just(UNIT))); + assertEquals(nothing(), result); + } + + @Test(timeout = 200) + public void checkedApplyFoldRightShortCircuit() { + Maybe result = Absent.absent().checkedApply(Constantly::constantly) + .foldRight(just(UNIT), repeat(nothing())).value(); + assertEquals(nothing(), result); + + result = Absent.absent().checkedApply(Constantly::constantly) + .foldRight(nothing(), repeat(just(UNIT))).value(); + assertEquals(nothing(), result); + } + + @Test(timeout = 200) + public void checkedApplyFoldLeftShortCircuit() { + Maybe result = Absent.absent().checkedApply(Constantly::constantly) + .foldLeft(just(UNIT), repeat(nothing())); + assertEquals(nothing(), result); + + result = Absent.absent().checkedApply(Constantly::constantly) + .foldLeft(nothing(), repeat(just(UNIT))); + assertEquals(nothing(), result); } } \ No newline at end of file From 31ad72636a68c37b2fb6988afb276dc20d8c1ab1 Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Sun, 9 May 2021 13:39:12 -0500 Subject: [PATCH 332/348] Add These::fromMaybes (#117) --- .../com/jnape/palatable/lambda/adt/These.java | 19 +++++++++++++++++++ .../jnape/palatable/lambda/adt/TheseTest.java | 11 +++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/adt/These.java b/src/main/java/com/jnape/palatable/lambda/adt/These.java index 6721d33e8..4fc4cc27b 100644 --- a/src/main/java/com/jnape/palatable/lambda/adt/These.java +++ b/src/main/java/com/jnape/palatable/lambda/adt/These.java @@ -189,6 +189,25 @@ public static These both(A a, B b) { return new Both<>(tuple(a, b)); } + /** + * Convenience method for converting a pair of {@link Maybe}s into a {@link Maybe} of {@link These}. If both + * {@link Maybe}s are {@link Maybe#just} then the result is a {@link Maybe#just} {@link These#both}. If only one + * {@link Maybe} is {@link Maybe#just} then it will be {@link Maybe#just} {@link These#a} or + * {@link Maybe#just} {@link These#b}. If both {@link Maybe}s are {@link Maybe#nothing} then the result will be + * {@link Maybe#nothing}. + * + * @param maybeA the first optional value + * @param maybeB the second optional value + * @param the first possible type + * @param the second possible type + * @return the wrapped values as a {@link Maybe}<{@link These}<A,B>> + */ + public static Maybe> fromMaybes(Maybe maybeA, Maybe maybeB) { + return maybeA.fmap(a -> maybeB.fmap(b -> both(a, b)).orElse(a(a))) + .fmap(Maybe::just) + .orElse(maybeB.fmap(These::b)); + } + /** * The canonical {@link Pure} instance for {@link These}. * diff --git a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java index 36a195011..e9f764d49 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/TheseTest.java @@ -12,9 +12,12 @@ import testsupport.traits.MonadRecLaws; import testsupport.traits.TraversableLaws; +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.These.a; import static com.jnape.palatable.lambda.adt.These.b; import static com.jnape.palatable.lambda.adt.These.both; +import static com.jnape.palatable.lambda.adt.These.fromMaybes; import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static com.jnape.palatable.traitor.framework.Subjects.subjects; import static org.junit.Assert.assertEquals; @@ -48,4 +51,12 @@ public void staticPure() { These these = These.pureThese().apply(1); assertEquals(b(1), these); } + + @Test + public void fromMaybesPermutations() { + assertEquals(nothing(), fromMaybes(nothing(), nothing())); + assertEquals(just(These.a(1)), fromMaybes(just(1), nothing())); + assertEquals(just(These.b(1)), fromMaybes(nothing(), just(1))); + assertEquals(just(These.both(1, "hello")), fromMaybes(just(1), just("hello"))); + } } \ No newline at end of file From eca9d40ef7a295c57c16b75086af04f9d7989282 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 31 Aug 2021 12:12:01 -0500 Subject: [PATCH 333/348] - WriterT#pure now has direct access to embedded monad's pure - EitherMatcher#isLeftOf/isRightOf for equality matching - updating CHANGELOG --- CHANGELOG.md | 13 ++++++++++-- .../monad/transformer/builtin/WriterT.java | 21 +++++++++++-------- .../testsupport/matchers/EitherMatcher.java | 9 ++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13f3971a8..314f61106 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,23 @@ # Change Log + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] +### Changed +- `Absent` folds short-circuit on the first `nothing()` +- `EitherMatcher#isLeftThat/isRightThat` support contravariant bounds on their delegates + ### Added +- `IterateT#runStep`, a method used to run a single step of an IterateT without the contractual guarantee of emitting a + value or reaching the end +- `These#fromMaybes :: Maybe a -> Maybe b -> Maybe (These a b)` +- `EitherMatcher#isLeftOf/isRightOf` for asserting equality -- `IterateT#runStep`, a method used to run a single step of an IterateT without the contractual - guarantee of emitting a value or reaching the end +### Fixed +- `WriterT` now keeps an immediate reference to the embedded monad's `pure` ## [5.3.0] - 2020-12-07 diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java index 7a0205543..c8625bbf8 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/WriterT.java @@ -34,9 +34,12 @@ public final class WriterT, A> implements MonadWriter>, MonadT, WriterT> { + private final Pure pureM; private final Fn1, ? extends MonadRec, M>> writerFn; - private WriterT(Fn1, ? extends MonadRec, M>> writerFn) { + private WriterT(Pure pureM, + Fn1, ? extends MonadRec, M>> writerFn) { + this.pureM = pureM; this.writerFn = writerFn; } @@ -82,7 +85,7 @@ public > MW execWriterT(Monoid monoid) { */ @Override public WriterT> listens(Fn1 fn) { - return new WriterT<>(writerFn.fmap(m -> m.fmap(into((a, w) -> both(both(constantly(a), fn), id(), w))))); + return new WriterT<>(pureM, writerFn.fmap(m -> m.fmap(into((a, w) -> both(both(constantly(a), fn), id(), w))))); } /** @@ -90,7 +93,7 @@ public WriterT> listens(Fn1 fn) { */ @Override public WriterT censor(Fn1 fn) { - return new WriterT<>(writerFn.fmap(mt -> mt.fmap(t -> t.fmap(fn)))); + return new WriterT<>(pureM, writerFn.fmap(mt -> mt.fmap(t -> t.fmap(fn)))); } /** @@ -107,7 +110,7 @@ public > WriterT lift(MonadRec mb) { @Override public WriterT trampolineM( Fn1, WriterT>> fn) { - return new WriterT<>(monoid -> runWriterT(monoid).trampolineM(into((a, w) -> fn.apply(a) + return new WriterT<>(pureM, monoid -> runWriterT(monoid).trampolineM(into((a, w) -> fn.apply(a) .>>coerce() .runWriterT(monoid).fmap(t -> t.fmap(monoid.apply(w))) .fmap(into((aOrB, w_) -> aOrB.biMap(a_ -> tuple(a_, w_), b -> tuple(b, w_))))))); @@ -126,7 +129,7 @@ public WriterT fmap(Fn1 fn) { */ @Override public WriterT pure(B b) { - return new WriterT<>(m -> runWriterT(m).pure(tuple(b, m.identity()))); + return new WriterT<>(pureM, m -> pureM.apply(tuple(b, m.identity()))); } /** @@ -134,7 +137,7 @@ public WriterT pure(B b) { */ @Override public WriterT flatMap(Fn1>> f) { - return new WriterT<>(monoid -> writerFn.apply(monoid) + return new WriterT<>(pureM, monoid -> writerFn.apply(monoid) .flatMap(into((a, w) -> f.apply(a).>coerce().runWriterT(monoid) .fmap(t -> t.fmap(monoid.apply(w)))))); } @@ -144,7 +147,7 @@ public WriterT flatMap(Fn1 WriterT zip(Applicative, WriterT> appFn) { - return new WriterT<>(monoid -> runWriterT(monoid) + return new WriterT<>(pureM, monoid -> runWriterT(monoid) .zip(appFn.>>coerce().runWriterT(monoid) .fmap(into((f, y) -> into((a, x) -> tuple(f.apply(a), monoid.apply(x, y))))))); } @@ -196,7 +199,7 @@ public static > WriterT tell(MonadRec, A> WriterT listen(MonadRec ma) { - return new WriterT<>(monoid -> ma.fmap(a -> tuple(a, monoid.identity()))); + return new WriterT<>(Pure.of(ma), monoid -> ma.fmap(a -> tuple(a, monoid.identity()))); } /** @@ -209,7 +212,7 @@ public static , A> WriterT listen(MonadRec< * @return the {@link WriterT} */ public static , A> WriterT writerT(MonadRec, M> maw) { - return new WriterT<>(constantly(maw)); + return new WriterT<>(Pure.of(maw), constantly(maw)); } /** diff --git a/src/test/java/testsupport/matchers/EitherMatcher.java b/src/test/java/testsupport/matchers/EitherMatcher.java index 2023a22b2..b18f68af6 100644 --- a/src/test/java/testsupport/matchers/EitherMatcher.java +++ b/src/test/java/testsupport/matchers/EitherMatcher.java @@ -10,6 +10,7 @@ import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.io.IO.io; import static org.hamcrest.CoreMatchers.anything; +import static org.hamcrest.CoreMatchers.equalTo; public final class EitherMatcher extends TypeSafeMatcher> { private final Either, Matcher> matcher; @@ -53,6 +54,10 @@ public static EitherMatcher isLeft() { return isLeftThat(anything()); } + public static EitherMatcher isLeftOf(L l) { + return isLeftThat(equalTo(l)); + } + public static EitherMatcher isRightThat(Matcher rMatcher) { return new EitherMatcher<>(right(rMatcher)); } @@ -60,4 +65,8 @@ public static EitherMatcher isRightThat(Matcher rMatcher public static EitherMatcher isRight() { return isRightThat(anything()); } + + public static EitherMatcher isRightOf(R r) { + return isRightThat(equalTo(r)); + } } From c3b262b38cc82ed4148662e1e343a67e81519a68 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 31 Aug 2021 12:20:24 -0500 Subject: [PATCH 334/348] [maven-release-plugin] prepare release lambda-5.4.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cc4cfc72d..231ca6768 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.3.1-SNAPSHOT + 5.4.0 jar Lambda From 0d2d287349acc657918387898c56ff1e071b37d5 Mon Sep 17 00:00:00 2001 From: jnape Date: Tue, 31 Aug 2021 12:20:26 -0500 Subject: [PATCH 335/348] [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 231ca6768..6f7735144 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.4.0 + 5.4.1-SNAPSHOT jar Lambda From 6ce542df28a94ad69e72b226564610b4d8919cfa Mon Sep 17 00:00:00 2001 From: jnape Date: Sat, 18 Sep 2021 13:19:54 -0500 Subject: [PATCH 336/348] Updating README and CHANGELOG --- CHANGELOG.md | 7 ++++++- README.md | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 314f61106..2d56ef532 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] +There are currently no unreleased changes + +## [5.4.0] - 2021-09-17 + ### Changed - `Absent` folds short-circuit on the first `nothing()` - `EitherMatcher#isLeftThat/isRightThat` support contravariant bounds on their delegates @@ -592,7 +596,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-5.3.0...HEAD +[Unreleased]: https://github.com/palatable/lambda/compare/lambda-5.4.0...HEAD +[5.4.0]: https://github.com/palatable/lambda/compare/lambda-5.3.0...lambda-5.4.0 [5.3.0]: https://github.com/palatable/lambda/compare/lambda-5.2.0...lambda-5.3.0 [5.2.0]: https://github.com/palatable/lambda/compare/lambda-5.1.0...lambda-5.2.0 [5.1.0]: https://github.com/palatable/lambda/compare/lambda-5.0.0...lambda-5.1.0 diff --git a/README.md b/README.md index 060d4e9ee..850dcfb8f 100644 --- a/README.md +++ b/README.md @@ -61,14 +61,14 @@ Add the following dependency to your: com.jnape.palatable lambda - 5.3.0 + 5.4.0 ``` `build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)): ```gradle -compile group: 'com.jnape.palatable', name: 'lambda', version: '5.3.0' +compile group: 'com.jnape.palatable', name: 'lambda', version: '5.4.0' ``` Examples From 5e73e1f77c826c6342792186afdab351a6c40def Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Thu, 10 Mar 2022 18:00:38 -0600 Subject: [PATCH 337/348] Add ReaderT#ask (#119) --- .../lambda/monad/transformer/builtin/ReaderT.java | 13 +++++++++++++ .../monad/transformer/builtin/ReaderTTest.java | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java index e7f93a168..e4c8ec5f0 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderT.java @@ -204,6 +204,19 @@ public ReaderT> carry() { return (ReaderT>) Cartesian.super.carry(); } + /** + * Given a {@link Pure} ask will give you access to the input within the monadic embedding + * + * @param pureM the {@link Pure} instance for the given {@link Monad} + * @param the input and output type of the returned ReaderT + * @param the returned {@link Monad} + * @return the {@link ReaderT} + */ + public static > ReaderT ask(Pure pureM) { + //noinspection Convert2MethodRef + return readerT(a -> pureM.apply(a)); + } + /** * Lift a {@link Fn1 function} (R -> {@link Monad}<A, M>) into a {@link ReaderT} instance. * diff --git a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java index cbcf1ef8b..983e7113a 100644 --- a/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monad/transformer/builtin/ReaderTTest.java @@ -97,4 +97,11 @@ public void fmapInteractions() { readerT.fmap(plusOne).fmap(plusOne).fmap(plusOne).runReaderT(0); assertEquals(1, invocations.get()); } + + @Test + public void askRetrievesInput() { + assertEquals(new Identity<>(1), + ReaderT.>ask(pureIdentity()) + .>runReaderT(1)); + } } \ No newline at end of file From 418cfa108db54f27aaaa4a2e56ee87ec95a62f56 Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Sun, 13 Mar 2022 19:09:40 -0500 Subject: [PATCH 338/348] Fix DropWhile fusion bug (#120) --- .../iteration/PredicatedDroppingIterable.java | 17 +++++-------- .../iteration/PredicatedDroppingIterator.java | 25 +++++++++++-------- .../iteration/RewindableIterator.java | 4 +-- .../functions/builtin/fn2/DropWhileTest.java | 10 ++++++-- .../PredicatedDroppingIteratorTest.java | 5 +++- .../iteration/RewindableIteratorTest.java | 6 +++-- 6 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java index d87cf0e09..ea7b68bc7 100644 --- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterable.java @@ -1,24 +1,20 @@ package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.internal.ImmutableQueue; -import java.util.ArrayList; import java.util.Iterator; -import java.util.List; - -import static com.jnape.palatable.lambda.functions.builtin.fn2.Any.any; -import static java.util.Collections.singletonList; public final class PredicatedDroppingIterable implements Iterable { - private final List> predicates; - private final Iterable as; + private final ImmutableQueue> predicates; + private final Iterable as; public PredicatedDroppingIterable(Fn1 predicate, Iterable as) { - List> predicates = new ArrayList<>(singletonList(predicate)); + ImmutableQueue> predicates = ImmutableQueue.singleton(predicate); while (as instanceof PredicatedDroppingIterable) { PredicatedDroppingIterable nested = (PredicatedDroppingIterable) as; as = nested.as; - predicates.addAll(0, nested.predicates); + predicates = nested.predicates.concat(predicates); } this.predicates = predicates; this.as = as; @@ -26,7 +22,6 @@ public PredicatedDroppingIterable(Fn1 predicate, I @Override public Iterator iterator() { - Fn1 metaPredicate = a -> any(p -> p.apply(a), predicates); - return new PredicatedDroppingIterator<>(metaPredicate, as.iterator()); + return new PredicatedDroppingIterator<>(predicates, as.iterator()); } } diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java index 7add62a45..a97b513ac 100644 --- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIterator.java @@ -1,19 +1,18 @@ package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.internal.ImmutableQueue; import java.util.Iterator; import java.util.NoSuchElementException; public final class PredicatedDroppingIterator extends ImmutableIterator { - private final Fn1 predicate; - private final RewindableIterator rewindableIterator; - private boolean finishedDropping; + private final Iterator> predicates; + private final RewindableIterator rewindableIterator; - public PredicatedDroppingIterator(Fn1 predicate, Iterator asIterator) { - this.predicate = predicate; + public PredicatedDroppingIterator(ImmutableQueue> predicates, Iterator asIterator) { + this.predicates = predicates.iterator(); rewindableIterator = new RewindableIterator<>(asIterator); - finishedDropping = false; } @Override @@ -31,11 +30,17 @@ public A next() { } private void dropElementsIfNecessary() { - while (rewindableIterator.hasNext() && !finishedDropping) { - if (!predicate.apply(rewindableIterator.next())) { - rewindableIterator.rewind(); - finishedDropping = true; + while (predicates.hasNext() && rewindableIterator.hasNext()) { + Fn1 predicate = predicates.next(); + boolean predicateDone = false; + + while (rewindableIterator.hasNext() && !predicateDone) { + if (!predicate.apply(rewindableIterator.next())) { + rewindableIterator.rewind(); + predicateDone = true; + } } + } } } diff --git a/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java index 5bdde4312..092e7e98b 100644 --- a/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java +++ b/src/main/java/com/jnape/palatable/lambda/internal/iteration/RewindableIterator.java @@ -54,9 +54,7 @@ public A retrieve() { if (cache == null) throw new NoSuchElementException("Cache is empty."); - A cache = this.cache; - this.cache = null; - return cache; + return this.cache; } public boolean isEmpty() { 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 83903f451..ff4551a11 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 @@ -56,7 +56,13 @@ public void deforestingExecutesPredicatesInOrder() { innerInvocations.add(x); return x > 2; }, asList(1, 2, 3))).forEach(__ -> {}); - assertThat(innerInvocations, iterates(1, 2, 3)); - assertThat(outerInvocations, iterates(1, 2)); + assertThat(innerInvocations, iterates(1)); + assertThat(outerInvocations, iterates(1, 2, 3)); + } + + @Test + public void eachLayerIsAppliedOnce() { + assertThat(dropWhile(i -> i % 2 == 0, dropWhile(i -> i % 2 == 1, asList(1, 2, 3))), + iterates(3)); } } diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java index 7fb0613c3..44fcde9f1 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/PredicatedDroppingIteratorTest.java @@ -1,15 +1,18 @@ package com.jnape.palatable.lambda.internal.iteration; import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.internal.ImmutableQueue; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; +import static java.util.Collections.singletonList; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static testsupport.Mocking.mockIteratorToHaveValues; @@ -25,7 +28,7 @@ public class PredicatedDroppingIteratorTest { @Before public void setUp() { - predicatedDroppingIterator = new PredicatedDroppingIterator<>(EVEN, iterator); + predicatedDroppingIterator = new PredicatedDroppingIterator<>(ImmutableQueue.singleton(EVEN), iterator); } @Test diff --git a/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java index 33bda1ad4..f07fe55a5 100644 --- a/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java +++ b/src/test/java/com/jnape/palatable/lambda/internal/iteration/RewindableIteratorTest.java @@ -10,6 +10,7 @@ import java.util.NoSuchElementException; import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static testsupport.Mocking.mockIteratorToHaveValues; @@ -51,13 +52,14 @@ public void cannotRewindIfNoValuesIterated() { rewindableIterator.rewind(); } - @Test(expected = NoSuchElementException.class) - public void cannotRewindTheSameElementTwice() { + @Test + public void canRewindTheSameElementTwice() { mockIteratorToHaveValues(iterator, 1, 2, 3); rewindableIterator.next(); rewindableIterator.rewind(); rewindableIterator.next(); rewindableIterator.rewind(); + assertEquals(1, rewindableIterator.next()); } @Test From 8a85105879ca654b646a0c3398c6ce803062af33 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Mar 2022 19:18:53 -0500 Subject: [PATCH 339/348] Updating CHANGELOG --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d56ef532..3aecf9b88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ## [Unreleased] -There are currently no unreleased changes +### Added +- `ReaderT#ask`, a static factory method for returning an identity `ReaderT` + +### Fixed +- nested `DropWhile`s no longer incorrectly deforest using disjunction ## [5.4.0] - 2021-09-17 From 0423ec9cf29423ea992eb01cbf36a5a1d950872e Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Mar 2022 19:21:30 -0500 Subject: [PATCH 340/348] [maven-release-plugin] prepare release lambda-5.5.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6f7735144..d713a9681 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.4.1-SNAPSHOT + 5.5.0 jar Lambda From abf79ddfe80cb8317dd2ff6bbd7cdca298984d55 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 13 Mar 2022 19:21:32 -0500 Subject: [PATCH 341/348] [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 d713a9681..a44d3b634 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 5.5.0 + 5.5.1-SNAPSHOT jar Lambda From 6e92250ee4f8b32388cb82d13c94a4613d42d123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Ho=C3=9F?= Date: Sat, 12 Nov 2022 15:05:43 +0100 Subject: [PATCH 342/348] add automatic module name to jar manifest This allows downstream projects using lambda to publish their own jars as modules without switching lambda itself to a jigsaw module. --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index a44d3b634..bae03b1e3 100644 --- a/pom.xml +++ b/pom.xml @@ -103,6 +103,13 @@ org.apache.maven.plugins maven-jar-plugin ${maven-jar-plugin.version} + + + + com.jnape.palatable.lambda + + + From 778fdfc42b3636c07aad70aac59440a9134fc64a Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Fri, 25 Nov 2022 20:21:28 -0600 Subject: [PATCH 343/348] GitHub action CI for prs (#124) * Enable CI for pull requests * Remove travis config --- .github/workflows/maven.yml | 4 +++- .travis.yml | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 873d5ac83..296a02977 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,6 +1,8 @@ name: Java CI -on: [push] +on: + push: + pull_request: jobs: build-java-1_8: diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 39074daea..000000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -dist: trusty -language: java -jdk: - - oraclejdk8 - - openjdk11 From edec5808c7863db98a4a9d41859044e0d2fb9e39 Mon Sep 17 00:00:00 2001 From: John Napier Date: Fri, 25 Nov 2022 20:22:15 -0600 Subject: [PATCH 344/348] Update README.md Removed travis build badge from README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 850dcfb8f..a1d7400bc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ λ ====== -[![Build Status](https://travis-ci.com/palatable/lambda.svg?branch=master)](https://travis-ci.com/palatable/lambda) [![Actions Status](https://github.com/palatable/lambda/workflows/Java%20CI/badge.svg)](https://github.com/palatable/lambda/actions) [![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda) [![Join the chat at https://gitter.im/palatable/lambda](https://badges.gitter.im/palatable/lambda.svg)](https://gitter.im/palatable/lambda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) From 3fe363976c57d7613e4052c45d3e02b1571446f8 Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Fri, 2 Dec 2022 15:03:57 -0600 Subject: [PATCH 345/348] Fix Absent::foldLeft bug (#121) Co-authored-by: Alexander Bandukwala Co-authored-by: Skyler Lutz --- .../jnape/palatable/lambda/semigroup/builtin/Absent.java | 2 +- .../palatable/lambda/semigroup/builtin/AbsentTest.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java index 68162ad74..222a5e7dc 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java @@ -72,7 +72,7 @@ public Maybe checkedApply(Maybe maybeX, Maybe maybeY) { @Override public Maybe foldLeft(Maybe acc, Iterable> maybes) { return trampoline( - into((res, it) -> res.equals(nothing()) + into((res, it) -> res.equals(nothing()) || !it.hasNext() ? terminate(res) : recurse(tuple(liftA2(aSemigroup, res, it.next()), it))), tuple(acc, maybes.iterator())); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java index 5ab7b53f6..9d3dc4524 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/builtin/AbsentTest.java @@ -71,6 +71,13 @@ public void foldLeftShortCircuit() { assertEquals(nothing(), result); } + @Test + public void foldLeftWorksForJusts() { + Maybe result = Absent.absent(Constantly::constantly) + .foldLeft(just(UNIT), Arrays.asList(just(UNIT), just(UNIT))); + assertEquals(just(UNIT), result); + } + @Test(timeout = 200) public void checkedApplyFoldRightShortCircuit() { Maybe result = Absent.absent().checkedApply(Constantly::constantly) From 88e70febbe69067778242364d2398f897d725fe6 Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Fri, 31 Mar 2023 17:38:21 -0500 Subject: [PATCH 346/348] Switch chat badge to point to palatable discord --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1d7400bc..11afcbe37 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ====== [![Actions Status](https://github.com/palatable/lambda/workflows/Java%20CI/badge.svg)](https://github.com/palatable/lambda/actions) [![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda) -[![Join the chat at https://gitter.im/palatable/lambda](https://badges.gitter.im/palatable/lambda.svg)](https://gitter.im/palatable/lambda?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat on Discord](https://dcbadge.vercel.app/api/server/wR7k8RAKM5)](https://discord.gg/wR7k8RAKM5) [![Floobits Status](https://floobits.com/jnape/lambda.svg)](https://floobits.com/jnape/lambda/redirect) Functional patterns for Java From e4831180484a9b7eca8a7cbacff5dc1c3b0ed2ca Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Fri, 31 Mar 2023 17:49:49 -0500 Subject: [PATCH 347/348] Fix height of discord badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 11afcbe37..7d84c6295 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ====== [![Actions Status](https://github.com/palatable/lambda/workflows/Java%20CI/badge.svg)](https://github.com/palatable/lambda/actions) [![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda) -[![Join the chat on Discord](https://dcbadge.vercel.app/api/server/wR7k8RAKM5)](https://discord.gg/wR7k8RAKM5) +[Join the chat on Discord](https://discord.gg/wR7k8RAKM5) [![Floobits Status](https://floobits.com/jnape/lambda.svg)](https://floobits.com/jnape/lambda/redirect) Functional patterns for Java From c1d2193ebdbbac8b0b31bec9bdcbfbd5820858ff Mon Sep 17 00:00:00 2001 From: Alexander Bandukwala <7h3kk1d@gmail.com> Date: Thu, 20 Apr 2023 21:36:44 -0500 Subject: [PATCH 348/348] FoldRight fixes for Monoid/Semigroup - Semigroup::foldRight had parameters flipped - Monoid::foldRight was accumulating the accumulator from the left. This has been fixed but the identity is now being used as a starting accumulator. Otherwise, the evaluation order is unchanged. - Changed ExplainFold parameter name since accumulator can be in either position --- .../java/com/jnape/palatable/lambda/monoid/Monoid.java | 2 +- .../com/jnape/palatable/lambda/semigroup/Semigroup.java | 2 +- .../lambda/functions/builtin/fn3/FoldRightTest.java | 2 +- .../com/jnape/palatable/lambda/monoid/MonoidTest.java | 9 +++++++++ .../jnape/palatable/lambda/semigroup/SemigroupTest.java | 9 +++++---- src/test/java/testsupport/functions/ExplainFold.java | 2 +- 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java index 8ecf83775..59f4ce1c7 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/Monoid.java @@ -82,7 +82,7 @@ default A foldLeft(A a, Iterable as) { */ @Override default Lazy foldRight(A a, Iterable as) { - return lazy(() -> flip().foldMap(id(), reverse(cons(a, as)))); + return lazy(() -> flip().foldMap(id(), cons(a, reverse(as)))); } /** diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java b/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java index a061328ce..d4cc1e6b4 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/Semigroup.java @@ -39,7 +39,7 @@ default A foldLeft(A a, Iterable as) { * @see FoldRight */ default Lazy foldRight(A a, Iterable as) { - return FoldRight.foldRight((y, lazyX) -> lazyX.fmap(x -> apply(x, y)), lazy(a), as); + return FoldRight.foldRight((y, lazyX) -> lazyX.fmap(x -> apply(y, x)), lazy(a), as); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java index 912ee9b4a..62f6d43c9 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn3/FoldRightTest.java @@ -29,7 +29,7 @@ public Fn1, Iterable> createTestSubject() { @Test public void foldRightAccumulatesRightToLeft() { - assertThat(foldRight((a, lazyB) -> lazyB.fmap(b -> explainFold().apply(a, b)), + assertThat(foldRight((a, lazyAcc) -> lazyAcc.fmap(acc -> explainFold().apply(a, acc)), lazy("5"), asList("1", "2", "3", "4")) .value(), diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/MonoidTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/MonoidTest.java index 87cfced3e..135d87195 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/MonoidTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/MonoidTest.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.monoid; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.builtin.Lazy; import org.junit.Test; import java.util.List; @@ -10,6 +11,7 @@ import static com.jnape.palatable.lambda.monoid.Monoid.monoid; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; +import static testsupport.functions.ExplainFold.explainFold; public class MonoidTest { @@ -25,6 +27,13 @@ public void reduceRight() { assertEquals((Integer) 6, sum.reduceRight(asList(1, 2, 3))); } + @Test + public void foldRight() { + Lazy lazyString = monoid(explainFold()::apply, "0") + .foldRight("4", asList("1", "2", "3")); + assertEquals("(1 + (2 + (3 + (4 + 0))))", lazyString.value()); + } + @Test public void foldMap() { Monoid sum = monoid(Integer::sum, 0); diff --git a/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java b/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java index 3291b6b1b..712c09e02 100644 --- a/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java +++ b/src/test/java/com/jnape/palatable/lambda/semigroup/SemigroupTest.java @@ -4,18 +4,19 @@ import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; +import static testsupport.functions.ExplainFold.explainFold; public class SemigroupTest { @Test public void foldLeft() { - Semigroup sum = (x, y) -> x + y; - assertEquals((Integer) 6, sum.foldLeft(0, asList(1, 2, 3))); + Semigroup foldFn = explainFold()::apply; + assertEquals("(((0 + 1) + 2) + 3)", foldFn.foldLeft("0", asList("1", "2", "3"))); } @Test public void foldRight() { - Semigroup sum = (x, y) -> x + y; - assertEquals((Integer) 6, sum.foldRight(0, asList(1, 2, 3)).value()); + Semigroup foldFn = explainFold()::apply; + assertEquals("(1 + (2 + (3 + 0)))", foldFn.foldRight("0", asList("1", "2", "3")).value()); } } \ No newline at end of file diff --git a/src/test/java/testsupport/functions/ExplainFold.java b/src/test/java/testsupport/functions/ExplainFold.java index d59a2378b..ba5c29527 100644 --- a/src/test/java/testsupport/functions/ExplainFold.java +++ b/src/test/java/testsupport/functions/ExplainFold.java @@ -7,6 +7,6 @@ public class ExplainFold { public static Fn2 explainFold() { - return (acc, x) -> format("(%s + %s)", acc, x); + return (x, y) -> format("(%s + %s)", x, y); } }

, F extends Functor, FB extends Functor, FT extends Functor, PAFB extends Profunctor, @@ -110,23 +110,27 @@ default Iso pure(U u) { } @Override - default Iso zip(Applicative, LensLike> appFn) { + default Iso zip( + Applicative, LensLike>> appFn) { return LensLike.super.zip(appFn).coerce(); } @Override - default Iso discardL(Applicative> appB) { + default Iso discardL(Applicative>> appB) { return LensLike.super.discardL(appB).coerce(); } @Override - default Iso discardR(Applicative> appB) { + default Iso discardR(Applicative>> appB) { return LensLike.super.discardR(appB).coerce(); } @Override - default Iso flatMap(Function>> fn) { - return unIso().fmap(bt -> Fn2.fn2(fn1(bt.andThen(fn.>andThen(Applicative::coerce)) + @SuppressWarnings("RedundantTypeArguments") + default Iso flatMap( + Function>>> fn) { + return unIso().fmap(bt -> Fn2.fn2(fn1(bt.andThen( + fn.>andThen(Monad>>::coerce)) .andThen(Iso::unIso) .andThen(Tuple2::_2) .andThen(Fn1::fn1)))) @@ -255,7 +259,7 @@ static Iso.Simple simpleIso(Function f, Fun * @param the type of both "smaller" values */ @FunctionalInterface - interface Simple extends Iso, LensLike.Simple { + interface Simple extends Iso, LensLike.Simple> { /** * Compose two simple isos from right to left. @@ -264,6 +268,7 @@ interface Simple extends Iso, LensLike.Simple { * @param the other simple iso' larger type * @return the composed simple iso */ + @SuppressWarnings("overloads") default Iso.Simple compose(Iso.Simple g) { return Iso.Simple.adapt(Iso.super.compose(g)); } @@ -275,6 +280,7 @@ default Iso.Simple compose(Iso.Simple g) { * @param the other simple iso' smaller type * @return the composed simple iso */ + @SuppressWarnings("overloads") default Iso.Simple andThen(Iso.Simple f) { return adapt(f.compose(this)); } @@ -290,7 +296,7 @@ default Lens.Simple toLens() { } @Override - default Iso.Simple discardR(Applicative> appB) { + default Iso.Simple discardR(Applicative>> appB) { return adapt(Iso.super.discardR(appB)); } 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 ba74b982a..edcb93650 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/Lens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/Lens.java @@ -137,7 +137,7 @@ * @param the type of the "smaller" update value */ @FunctionalInterface -public interface Lens extends LensLike { +public interface Lens extends LensLike> { @Override default Lens fmap(Function fn) { @@ -150,22 +150,24 @@ default Lens pure(U u) { } @Override - default Lens zip(Applicative, LensLike> appFn) { + default Lens zip( + Applicative, LensLike>> appFn) { return LensLike.super.zip(appFn).coerce(); } @Override - default Lens discardL(Applicative> appB) { + default Lens discardL(Applicative>> appB) { return LensLike.super.discardL(appB).coerce(); } @Override - default Lens discardR(Applicative> appB) { + default Lens discardR(Applicative>> appB) { return LensLike.super.discardR(appB).coerce(); } @Override - default Lens flatMap(Function>> f) { + default Lens flatMap( + Function>>> f) { return lens(view(this), (s, b) -> set(f.apply(set(this, b, s)).>coerce(), b, s)); } @@ -307,7 +309,7 @@ static Lens.Simple> both(Lens.Simple f, Lens.Sim * @param the type of both "smaller" values */ @FunctionalInterface - interface Simple extends Lens, LensLike.Simple { + interface Simple extends Lens, LensLike.Simple> { default Lens.Simple compose(LensLike.Simple g) { return Lens.Simple.adapt(Lens.super.compose(g)); diff --git a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java b/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java index 4975544ba..d0c4647f1 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/LensLike.java @@ -20,7 +20,7 @@ * @see Lens * @see Iso */ -public interface LensLike extends +public interface LensLike> extends Monad>, Profunctor> { @@ -138,7 +138,7 @@ default LensLike contraMap(Function * @param the "smaller" type * @param the concrete lens subtype */ - interface Simple extends LensLike { + interface Simple> extends LensLike { /** * Compose two simple lenses from right to left. diff --git a/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java b/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java index b43c0e596..10c54dca9 100644 --- a/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java +++ b/src/main/java/com/jnape/palatable/lambda/lens/lenses/CollectionLens.java @@ -63,9 +63,10 @@ public static > Lens.Simple> asSet( * @param the type of the collection * @return a lens that focuses on a Collection as a stream. */ + @SuppressWarnings("RedundantTypeArguments") public static > Lens.Simple> asStream( Function copyFn) { - return simpleLens(Collection::stream, (xsL, xsS) -> { + return simpleLens(Collection::stream, (xsL, xsS) -> { CX updated = copyFn.apply(xsL); updated.clear(); xsS.forEach(updated::add); diff --git a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java index ef1e26a2b..1b251f51a 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java @@ -62,9 +62,11 @@ default Monad zip(Applicative, M> app /** * {@inheritDoc} + * @param lazyAppFn */ @Override - default Lazy> lazyZip(Lazy, M>> lazyAppFn) { + default Lazy> lazyZip( + Lazy, M>> lazyAppFn) { return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); } diff --git a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java index cccf15d1b..2fc0731d5 100644 --- a/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java +++ b/src/main/java/com/jnape/palatable/lambda/monoid/builtin/Present.java @@ -29,7 +29,7 @@ */ public final class Present implements MonoidFactory, Maybe> { - private static final Present INSTANCE = new Present<>(); + private static final Present INSTANCE = new Present<>(); private Present() { } @@ -42,7 +42,7 @@ public Monoid> apply(Semigroup aSemigroup) { @SuppressWarnings("unchecked") public static Present present() { - return INSTANCE; + return (Present) INSTANCE; } public static Monoid> present(Semigroup semigroup) { diff --git a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java index f2991e238..1e8c6ef1c 100644 --- a/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java +++ b/src/main/java/com/jnape/palatable/lambda/semigroup/builtin/Absent.java @@ -25,7 +25,7 @@ */ public final class Absent implements SemigroupFactory, Maybe> { - private static final Absent INSTANCE = new Absent<>(); + private static final Absent INSTANCE = new Absent<>(); private Absent() { } @@ -37,7 +37,7 @@ public Semigroup> apply(Semigroup aSemigroup) { @SuppressWarnings("unchecked") public static Absent absent() { - return INSTANCE; + return (Absent) INSTANCE; } public static Semigroup> absent(Semigroup semigroup) { 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 81928dc81..5ef35da8e 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaIterable.java @@ -73,13 +73,15 @@ public LambdaIterable zip(Applicative, L /** * {@inheritDoc} + * + * @param lazyAppFn */ @Override public Lazy> lazyZip( - Lazy, LambdaIterable>> lazyAppFn) { + Lazy, LambdaIterable>> lazyAppFn) { return Empty.empty(as) ? lazy(LambdaIterable.empty()) - : Monad.super.lazyZip(lazyAppFn).fmap(Applicative::coerce); + : Monad.super.lazyZip(lazyAppFn).fmap(Monad>::coerce); } /** @@ -129,7 +131,7 @@ AppTrav extends Applicative> AppTrav traverse(Function xs = as.iterator(); - Iterator ys = ((LambdaIterable) other).as.iterator(); + Iterator ys = ((LambdaIterable) other).as.iterator(); while (xs.hasNext() && ys.hasNext()) if (!Objects.equals(xs.next(), ys.next())) diff --git a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java index 5b683de69..9c9152f87 100644 --- a/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java +++ b/src/main/java/com/jnape/palatable/lambda/traversable/LambdaMap.java @@ -53,7 +53,7 @@ AppTrav extends Applicative> AppTrav traverse(Function, AppTrav>fn2( appTrav -> into((k, appV) -> (AppTrav) appTrav.zip(appV.fmap(v -> m -> { ((LambdaMap) m).unwrap().put(k, v); - return (TravC) m; + return m; })))).toBiFunction(), pure.apply((TravC) LambdaMap.wrap(new HashMap<>())), this.fmap(fn).unwrap().entrySet()); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java index 56d3c19d5..aae10e80e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/SingletonHListTest.java @@ -25,7 +25,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) - public SingletonHList testSubject() { + public SingletonHList testSubject() { return singletonHList("one"); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java index a5e86f825..a72f4843a 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple2Test.java @@ -34,7 +34,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple2 testSubject() { + public Tuple2 testSubject() { return tuple("one", 2); } @@ -93,6 +93,7 @@ public void setValueIsNotSupported() { } @Test + @SuppressWarnings("serial") public void staticFactoryMethodFromMapEntry() { Map.Entry stringIntEntry = new HashMap() {{ put("string", 1); diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java index 0730a97a9..8ca30d9af 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple3Test.java @@ -31,7 +31,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple3 testSubject() { + public Tuple3 testSubject() { return tuple("one", 2, 3d); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java index 44a6ba8dc..7eff60484 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple4Test.java @@ -31,7 +31,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple4 testSubject() { + public Tuple4 testSubject() { return tuple("one", 2, 3d, 4f); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java index 248dd03e1..22d30223d 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple5Test.java @@ -32,7 +32,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple5 testSubject() { + public Tuple5 testSubject() { return tuple("one", 2, 3d, 4f, '5'); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java index bd31aca1a..af12149e6 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple6Test.java @@ -32,7 +32,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple6 testSubject() { + public Tuple6 testSubject() { return tuple("one", 2, 3d, 4f, '5', (byte) 6); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java index a62a36691..f4fd5442e 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple7Test.java @@ -32,7 +32,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple7 testSubject() { + public Tuple7 testSubject() { return tuple("one", 2, 3d, 4f, '5', (byte) 6, 7L); } diff --git a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java index c19ee8a58..327fb8fe3 100644 --- a/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java +++ b/src/test/java/com/jnape/palatable/lambda/adt/hlist/Tuple8Test.java @@ -32,7 +32,7 @@ public void setUp() { } @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Tuple8 testSubject() { + public Tuple8 testSubject() { return tuple("one", 2, 3d, 4f, '5', (byte) 6, 7L, (short) 65535); } 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 0c93ecb3f..9c2456ab8 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 @@ -156,11 +156,12 @@ public void demandForAbsentKey() { } @Test + @SuppressWarnings("serial") public void toMap() { TypeSafeKey stringKey = typeSafeKey(); TypeSafeKey intKey = typeSafeKey(); - assertEquals(new HashMap() {{ + assertEquals(new HashMap, Object>() {{ put(stringKey, "string"); put(intKey, 1); }}, hMap(stringKey, "string", @@ -263,7 +264,6 @@ public void convenienceStaticFactoryMethods() { } @Test - @SuppressWarnings("EqualsWithItself") public void equality() { assertEquals(emptyHMap(), emptyHMap()); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CycleTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CycleTest.java index f9acf8d22..d9c04a459 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CycleTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/CycleTest.java @@ -17,7 +17,7 @@ public class CycleTest { @TestTraits({Laziness.class, ImmutableIteration.class, InfiniteIteration.class}) - public Cycle createTestSubject() { + public Cycle createTestSubject() { return cycle(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DistinctTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DistinctTest.java index 4755af103..b535e381c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DistinctTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/DistinctTest.java @@ -19,7 +19,7 @@ public class DistinctTest { @TestTraits({Laziness.class, InfiniteIterableSupport.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Distinct testSubject() { + public Distinct testSubject() { return distinct(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitTest.java index dde20b9fe..b27b65903 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitTest.java @@ -23,7 +23,7 @@ public class InitTest { @TestTraits({EmptyIterableSupport.class, InfiniteIterableSupport.class, Laziness.class, ImmutableIteration.class, FiniteIteration.class}) - public Fn1 testSubject() { + public Fn1, ? extends Iterable> testSubject() { return init(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitsTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitsTest.java index 191425e2c..50b417d58 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitsTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/InitsTest.java @@ -22,7 +22,7 @@ public class InitsTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, InfiniteIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Fn1 testSubject() { + public Fn1, ? extends Iterable> testSubject() { return inits(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java index bb11d5782..290fa2736 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/OccurrencesTest.java @@ -2,17 +2,18 @@ import org.junit.Test; +import java.util.Collections; import java.util.HashMap; import static com.jnape.palatable.lambda.functions.builtin.fn1.Occurrences.occurrences; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; import static org.junit.Assert.assertEquals; public class OccurrencesTest { @Test + @SuppressWarnings("serial") public void occurrencesOfIndividualElements() { assertEquals(new HashMap() {{ put("foo", 2L); @@ -23,6 +24,6 @@ public void occurrencesOfIndividualElements() { @Test public void emptyIterableHasNoOccurrences() { - assertEquals(emptyMap(), occurrences(emptyList())); + assertEquals(Collections.emptyMap(), occurrences(emptyList())); } } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/RepeatTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/RepeatTest.java index 80112707f..de34c53b4 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/RepeatTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/RepeatTest.java @@ -17,7 +17,7 @@ public class RepeatTest { @TestTraits({Laziness.class, ImmutableIteration.class, InfiniteIteration.class}) - public Repeat createTestSubject() { + public Repeat createTestSubject() { return repeat(); } 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 308b9123e..434ed4ba2 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 @@ -24,7 +24,7 @@ public class ReverseTest { @TestTraits({Laziness.class, ImmutableIteration.class, FiniteIteration.class, EmptyIterableSupport.class}) - public Reverse createTestSubject() { + public Reverse createTestSubject() { return reverse(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java index 7ee079443..a0039dc3e 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/SizeTest.java @@ -21,6 +21,7 @@ public void countsElementsInIterable() { } @Test + @SuppressWarnings("serial") public void optimizesForCollections() { Collection collection = spy(new ArrayList() {{ add(1); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailTest.java index 055cd9c9b..57a854456 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailTest.java @@ -20,7 +20,7 @@ public class TailTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Fn1 createTraitsTestSubject() { + public Fn1, ?> createTraitsTestSubject() { return tail(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailsTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailsTest.java index 45b3a1b25..a384d21cc 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailsTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/TailsTest.java @@ -27,7 +27,7 @@ public class TailsTest { @TestTraits({EmptyIterableSupport.class, InfiniteIterableSupport.class, FiniteIteration.class, ImmutableIteration.class, Laziness.class}) - public Fn1 testSubject() { + public Fn1, ? extends Iterable> testSubject() { return tails(); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java index b3c8ece22..115ba8164 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn1/UnconsTest.java @@ -19,7 +19,7 @@ public class UnconsTest { @TestTraits({EmptyIterableSupport.class}) - public Uncons testSubject() { + public Uncons testSubject() { return uncons(); } 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 27e5fa0bd..73ca133bc 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 @@ -25,7 +25,7 @@ public class FilterTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Fn1 testSubject() { + public Fn1, ?> testSubject() { return filter(constantly(true)); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java index 02f8e8bf2..b04ea7999 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/GroupByTest.java @@ -2,6 +2,7 @@ import org.junit.Test; +import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -13,6 +14,7 @@ import static java.util.Collections.singletonList; import static org.junit.Assert.assertEquals; +@SuppressWarnings("serial") public class GroupByTest { @Test @@ -25,6 +27,6 @@ public void grouping() { @Test public void emptyIterableProducesEmptyMap() { - assertEquals(emptyMap(), groupBy(id(), emptyList())); + assertEquals(Collections.>emptyMap(), groupBy(id(), emptyList())); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IterateTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IterateTest.java index 961aa0d15..564290452 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IterateTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/IterateTest.java @@ -21,7 +21,7 @@ public class IterateTest { @TestTraits({Laziness.class, InfiniteIteration.class, ImmutableIteration.class}) - public Fn1 createTestSubject() { + public Fn1, ? extends Iterable> createTestSubject() { return iterate(constantly(new ArrayList<>())); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MapTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MapTest.java index 92a6e725b..4e7f8967c 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MapTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/MapTest.java @@ -21,7 +21,7 @@ public class MapTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, InfiniteIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Fn1 createTraitsTestSubject() { + public Fn1, ?> createTraitsTestSubject() { return map(id()); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java index 05366dfb4..8aad38db7 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/PartitionTest.java @@ -29,7 +29,7 @@ public class PartitionTest { @TestTraits({Laziness.class, EmptyIterableSupport.class, FiniteIteration.class, ImmutableIteration.class}) - public Subjects> createTraitsTestSubject() { + public Subjects, ?>> createTraitsTestSubject() { return subjects(partition(constantly(a(1))).andThen(Tuple2::_1), partition(constantly(b(1))).andThen(Tuple2::_2)); } diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMapTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMapTest.java index 21ab43c8d..2573212f6 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMapTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/ToMapTest.java @@ -13,6 +13,7 @@ public class ToMapTest { @Test + @SuppressWarnings("serial") public void collectsEntriesIntoMap() { Map expected = new HashMap() {{ put("foo", 1); diff --git a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UnfoldrTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UnfoldrTest.java index 95b0cf7c1..4c876912b 100644 --- a/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UnfoldrTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/UnfoldrTest.java @@ -23,7 +23,7 @@ public class UnfoldrTest { @TestTraits({Laziness.class, InfiniteIteration.class, ImmutableIteration.class}) - public Fn1 createTestSubject() { + public Fn1, ? extends Iterable> createTestSubject() { return unfoldr(x -> just(tuple(x, x))); } diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java index 45588a462..da90a8592 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ConstTest.java @@ -13,7 +13,7 @@ public class ConstTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, BifunctorLaws.class, TraversableLaws.class}) - public Const testSubject() { + public Const testSubject() { return new Const<>(1); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java index 7a46afd1d..242a5aaa0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/IdentityTest.java @@ -12,7 +12,7 @@ public class IdentityTest { @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class, TraversableLaws.class}) - public Identity testSubject() { + public Identity testSubject() { return new Identity<>(""); } } \ No newline at end of file diff --git a/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java b/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java index 003c7bda7..de5557f15 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java +++ b/src/test/java/com/jnape/palatable/lambda/lens/IsoTest.java @@ -1,6 +1,7 @@ package com.jnape.palatable.lambda.lens; import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.Functor; import com.jnape.palatable.lambda.functor.builtin.Const; import com.jnape.palatable.traitor.annotations.TestTraits; import com.jnape.palatable.traitor.runners.Traits; @@ -28,8 +29,12 @@ public class IsoTest { iso(Integer::parseInt, dbl -> dbl.toString().chars().mapToObj(x -> (char) x).collect(toList())); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, ?> testSubject() { - return new EquatableM<>(ISO, iso -> iso.apply(Const::new, "123")); + public EquatableM>, List> testSubject() { + return new EquatableM<>(ISO, iso -> { + @SuppressWarnings("UnnecessaryLocalVariable") + Functor> result = iso.apply(Const::new, "123"); + return result; + }); } @Test 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 7d609e980..4ab9622a9 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/lens/LensTest.java @@ -41,7 +41,7 @@ public class LensTest { LENS = lens(xs -> xs.get(0), (xs, i) -> singleton(i)); @TestTraits({FunctorLaws.class, ApplicativeLaws.class, MonadLaws.class}) - public EquatableM, ?, Integer, String, Lens>, ?> testSubject() { + public EquatableM, ?, Integer, String, Lens>, ?> testSubject() { return new EquatableM<>(lens(m -> m.get("foo"), (m, s) -> singletonList(m.get(s))), l -> view(l, emptyMap())); } diff --git a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java b/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java index 7a83e934a..800dcb876 100644 --- a/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java +++ b/src/test/java/com/jnape/palatable/lambda/lens/lenses/MapLensTest.java @@ -29,6 +29,7 @@ import static testsupport.assertion.LensAssert.assertLensLawfulness; import static testsupport.matchers.IterableMatcher.iterates; +@SuppressWarnings("serial") public class MapLensTest { @Test diff --git a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AddAllTest.java b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AddAllTest.java index 8a997382b..c1aaf214f 100644 --- a/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AddAllTest.java +++ b/src/test/java/com/jnape/palatable/lambda/monoid/builtin/AddAllTest.java @@ -13,6 +13,7 @@ public class AddAllTest { @Test + @SuppressWarnings("serial") public void monoid() { Monoid> addAll = addAll(HashSet::new); diff --git a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java index 9cffe9efb..2be8673f7 100644 --- a/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java +++ b/src/test/java/com/jnape/palatable/lambda/traversable/LambdaMapTest.java @@ -15,6 +15,7 @@ @RunWith(Traits.class) public class LambdaMapTest { + @SuppressWarnings("serial") @TestTraits({FunctorLaws.class, TraversableLaws.class}) public Subjects> testSubject() { return subjects(LambdaMap.empty(), diff --git a/src/test/java/testsupport/EquatableM.java b/src/test/java/testsupport/EquatableM.java index 72feb443d..ad4272ed8 100644 --- a/src/test/java/testsupport/EquatableM.java +++ b/src/test/java/testsupport/EquatableM.java @@ -55,4 +55,9 @@ public boolean equals(Object other) { } return false; } + + @Override + public int hashCode() { + return super.hashCode(); + } } diff --git a/src/test/java/testsupport/traits/EmptyIterableSupport.java b/src/test/java/testsupport/traits/EmptyIterableSupport.java index a0d2d029a..d30b57a3e 100644 --- a/src/test/java/testsupport/traits/EmptyIterableSupport.java +++ b/src/test/java/testsupport/traits/EmptyIterableSupport.java @@ -5,12 +5,12 @@ import java.util.ArrayList; -public class EmptyIterableSupport implements Trait> { +public class EmptyIterableSupport implements Trait, ?>> { @Override - public void test(Fn1 testSubject) { + public void test(Fn1, ?> testSubject) { try { - testSubject.apply(new ArrayList()); + testSubject.apply(new ArrayList<>()); } catch (Exception e) { throw new AssertionError("Expected support for empty iterable arguments", e); } diff --git a/src/test/java/testsupport/traits/FiniteIteration.java b/src/test/java/testsupport/traits/FiniteIteration.java index 882632f17..03168d2b6 100644 --- a/src/test/java/testsupport/traits/FiniteIteration.java +++ b/src/test/java/testsupport/traits/FiniteIteration.java @@ -8,11 +8,11 @@ import static org.hamcrest.core.Is.is; import static testsupport.matchers.FiniteIterableMatcher.finitelyIterable; -public class FiniteIteration implements Trait> { +public class FiniteIteration implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { - Iterable result = testSubject.apply(asList(1, 2, 3)); + public void test(Fn1, Iterable> testSubject) { + Iterable result = testSubject.apply(asList(1, 2, 3)); assertThat(result, is(finitelyIterable())); } } diff --git a/src/test/java/testsupport/traits/ImmutableIteration.java b/src/test/java/testsupport/traits/ImmutableIteration.java index ce6e7db55..d6a74737e 100644 --- a/src/test/java/testsupport/traits/ImmutableIteration.java +++ b/src/test/java/testsupport/traits/ImmutableIteration.java @@ -7,11 +7,11 @@ import static org.junit.Assert.fail; -public class ImmutableIteration implements Trait> { +public class ImmutableIteration implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { - Iterable result = testSubject.apply(new ArrayList()); + public void test(Fn1, Iterable> testSubject) { + Iterable result = testSubject.apply(new ArrayList<>()); try { result.iterator().remove(); fail("Expected remove() to throw Exception, but it didn't."); diff --git a/src/test/java/testsupport/traits/InfiniteIterableSupport.java b/src/test/java/testsupport/traits/InfiniteIterableSupport.java index 3c870f1ad..3c1131341 100644 --- a/src/test/java/testsupport/traits/InfiniteIterableSupport.java +++ b/src/test/java/testsupport/traits/InfiniteIterableSupport.java @@ -9,10 +9,10 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.fail; -public class InfiniteIterableSupport implements Trait> { +public class InfiniteIterableSupport implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { + public void test(Fn1, Iterable> testSubject) { CountDownLatch latch = new CountDownLatch(1); new Thread(() -> { testSubject.apply(repeat(0)).iterator().next(); diff --git a/src/test/java/testsupport/traits/InfiniteIteration.java b/src/test/java/testsupport/traits/InfiniteIteration.java index 12072fe78..085907ce2 100644 --- a/src/test/java/testsupport/traits/InfiniteIteration.java +++ b/src/test/java/testsupport/traits/InfiniteIteration.java @@ -9,11 +9,11 @@ import static org.hamcrest.core.Is.is; import static testsupport.matchers.FiniteIterableMatcher.finitelyIterable; -public class InfiniteIteration implements Trait> { +public class InfiniteIteration implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { - Iterable result = testSubject.apply(asList(1, 2, 3)); + public void test(Fn1, Iterable> testSubject) { + Iterable result = testSubject.apply(asList(1, 2, 3)); assertThat(result, is(not(finitelyIterable()))); } } diff --git a/src/test/java/testsupport/traits/Laziness.java b/src/test/java/testsupport/traits/Laziness.java index 216201df7..cd0a58b6c 100644 --- a/src/test/java/testsupport/traits/Laziness.java +++ b/src/test/java/testsupport/traits/Laziness.java @@ -7,11 +7,11 @@ import static testsupport.Mocking.mockIterable; import static testsupport.matchers.ZeroInvocationsMatcher.wasNeverInteractedWith; -public class Laziness implements Trait> { +public class Laziness implements Trait, Iterable>> { @Override - public void test(Fn1 testSubject) { - Iterable iterable = mockIterable(); + public void test(Fn1, Iterable> testSubject) { + Iterable iterable = mockIterable(); testSubject.apply(iterable); assertThat(iterable, wasNeverInteractedWith()); From 96ed8c0fafbc26efe6fbc176ab86a16e27555a86 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 14 Apr 2019 18:51:08 -0500 Subject: [PATCH 119/348] Compose lazyZip defers to outer applicative's lazyZip --- .../palatable/lambda/functor/builtin/Compose.java | 13 ++++++++++++- .../lambda/functor/builtin/ComposeTest.java | 12 ++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java index df6d857c2..b7dcbe209 100644 --- a/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java +++ b/src/main/java/com/jnape/palatable/lambda/functor/builtin/Compose.java @@ -5,6 +5,8 @@ import java.util.Objects; import java.util.function.Function; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; + /** * A functor representing the type-level composition of two {@link Applicative} functors; useful for preserving nested * type-level transformations during traversal of a {@link com.jnape.palatable.lambda.traversable.Traversable}. @@ -60,7 +62,16 @@ public Compose zip(Applicative, Co @Override public Lazy> lazyZip( Lazy, Compose>> lazyAppFn) { - return Applicative.super.lazyZip(lazyAppFn).fmap(Applicative>::coerce); + @SuppressWarnings("RedundantTypeArguments") + Lazy, G>, F>> lazyAppFnCoerced = + lazyAppFn + .>>fmap( + Applicative, Compose>::coerce) + .fmap(Compose>::getCompose); + + return fga.>fmap(upcast()) + .>lazyZip(lazyAppFnCoerced.fmap(fgf -> fgf.fmap(gf -> ga -> ga.zip(gf)))) + .fmap(Compose::new); } /** diff --git a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java index 66303c375..dc994a3b0 100644 --- a/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java +++ b/src/test/java/com/jnape/palatable/lambda/functor/builtin/ComposeTest.java @@ -9,8 +9,10 @@ import testsupport.traits.ApplicativeLaws; import testsupport.traits.FunctorLaws; +import static com.jnape.palatable.lambda.adt.Either.left; import static com.jnape.palatable.lambda.adt.Either.right; import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.functor.builtin.Lazy.lazy; import static org.junit.Assert.assertEquals; @RunWith(Traits.class) @@ -26,4 +28,14 @@ public void inference() { Either> a = new Compose<>(right(just(1))).fmap(x -> x + 1).getCompose(); assertEquals(right(just(2)), a); } + + @Test + public void lazyZip() { + assertEquals(new Compose<>(right(just(2))), + new Compose<>(right(just(1))).lazyZip(lazy(new Compose<>(right(just(x -> x + 1))))).value()); + assertEquals(new Compose<>(left("foo")), + new Compose<>(left("foo")).lazyZip(lazy(() -> { + throw new AssertionError(); + })).value()); + } } \ No newline at end of file From b006704e6a70e51f6270f208f233d5a26456bd55 Mon Sep 17 00:00:00 2001 From: jnape Date: Sun, 14 Apr 2019 19:59:04 -0500 Subject: [PATCH 120/348] MaybeT, a monad transformer for Maybe, and general MonadT --- CHANGELOG.md | 2 + .../jnape/palatable/lambda/monad/Monad.java | 1 - .../lambda/monad/transformer/MaybeT.java | 129 ++++++++++++++++++ .../lambda/monad/transformer/MonadT.java | 101 ++++++++++++++ .../lambda/monad/transformer/MaybeTTest.java | 41 ++++++ 5 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/transformer/MaybeT.java create mode 100644 src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java create mode 100644 src/test/java/com/jnape/palatable/lambda/monad/transformer/MaybeTTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index ec8477ed1..bf372699b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ might need to be reworked, and subtyping is obviously no longer supported. - `Lazy`, a monad supporting stack-safe lazy evaluation - `LazyRec`, a function for writing stack-safe recursive algorithms embedded in `Lazy` - `Applicative#lazyZip`, for zipping two applicatives in a way that might not require evaluation of one applicative +- `MonadT`, a general interface representing monad transformers +- `MaybeT`, a monad transformer for `Maybe` ## [3.3.0] - 2019-02-18 ### Added diff --git a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java index 1b251f51a..00aca101c 100644 --- a/src/main/java/com/jnape/palatable/lambda/monad/Monad.java +++ b/src/main/java/com/jnape/palatable/lambda/monad/Monad.java @@ -62,7 +62,6 @@ default Monad zip(Applicative, M> app /** * {@inheritDoc} - * @param lazyAppFn */ @Override default Lazy> lazyZip( diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MaybeT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MaybeT.java new file mode 100644 index 000000000..afbf56721 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MaybeT.java @@ -0,0 +1,129 @@ +package com.jnape.palatable.lambda.monad.transformer; + +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Compose; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.Objects; +import java.util.function.Function; + +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; + +/** + * A {@link MonadT monad transformer} for {@link Maybe}. + * + * @param the outer {@link Monad} + * @param the carrier type + */ +public final class MaybeT, A> implements MonadT, A> { + + private final Monad, M> mma; + + private MaybeT(Monad, M> mma) { + this.mma = mma; + } + + /** + * {@inheritDoc} + */ + @Override + public >, FGA extends Monad> FGA run() { + return mma.fmap(Applicative::coerce).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT fmap(Function fn) { + return MonadT.super.fmap(fn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT pure(B b) { + return maybeT(mma.pure(just(b))); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT zip(Applicative, MonadT, ?>> appFn) { + return MonadT.super.zip(appFn).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public Lazy> lazyZip( + Lazy, MonadT, ?>>> lazyAppFn) { + return new Compose<>(mma) + .lazyZip(lazyAppFn.fmap(maybeT -> new Compose<>( + maybeT.>>coerce().>, Monad>, M>>run()))) + .fmap(compose -> maybeT(compose.getCompose())); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT flatMap(Function, ?>>> f) { + return maybeT(mma.flatMap(ma -> ma + .match(constantly(mma.pure(nothing())), + a -> f.apply(a).>coerce().run()))); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT discardL(Applicative, ?>> appB) { + return MonadT.super.discardL(appB).coerce(); + } + + /** + * {@inheritDoc} + */ + @Override + public MaybeT discardR(Applicative, ?>> appB) { + return MonadT.super.discardR(appB).coerce(); + } + + @Override + public boolean equals(Object other) { + return other instanceof MaybeT && Objects.equals(mma, ((MaybeT) other).mma); + } + + @Override + public int hashCode() { + return Objects.hash(mma); + } + + @Override + public String toString() { + return "MaybeT{" + + "mma=" + mma + + '}'; + } + + /** + * Static factory method for lifting a {@link Monad}<{@link Maybe}<A>> into a + * {@link MaybeT}. + * + * @param mma the {@link Monad}<{@link Maybe}<A>> + * @param the outer {@link Monad} unification parameter + * @param the carrier type + * @return the {@link MaybeT} + */ + public static , A> MaybeT maybeT(Monad, M> mma) { + return new MaybeT<>(mma); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java new file mode 100644 index 000000000..8098d2ba6 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/MonadT.java @@ -0,0 +1,101 @@ +package com.jnape.palatable.lambda.monad.transformer; + +import com.jnape.palatable.lambda.functor.Applicative; +import com.jnape.palatable.lambda.functor.builtin.Lazy; +import com.jnape.palatable.lambda.monad.Monad; + +import java.util.function.Function; + +/** + * An interface representing a {@link Monad} transformer. + *

, F extends Functor, FB extends Functor, + FT extends Functor, PAFB extends Profunctor, + PSFT extends Profunctor> PSFT apply(PAFB pafb) { + return composed.apply(pafb); } @Override @@ -105,8 +107,9 @@ interface Simple extends TypeSafeKey { @Override @SuppressWarnings("unchecked") - default