diff --git a/CHANGELOG.md b/CHANGELOG.md index c49b53a53..e04438485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,42 @@ 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 +- ***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***: `Effect` 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 +- `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` +- `Fn0` now additionally implements `Callable` +- `CheckedRunnable` is an `IO` + +### Added +- `Predicate#predicate` static factory method +- `Product2-8` left/right rotation methods +- `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` +- `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 +- `IO` monad +- `RunAll` semigroup and monoid instance for `IO` + +### 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 - `Fn3-8` static factory overloads to aid in coercing lambdas - Adding composition guarantees to `LensLike` @@ -368,7 +404,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 diff --git a/pom.xml b/pom.xml index 6f0a6e0aa..a117dcaf0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ lambda - 3.1.0 + 3.2.0 jar Lambda 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..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; @@ -92,7 +93,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 +106,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))); } @@ -122,7 +124,7 @@ public final Either filter(Function pred, Function Either flatMap(Function>> rightFn) { - return flatMap(Either::left, rightFn.andThen(Applicative::coerce)); + return match(Either::left, rightFn.andThen(Applicative::coerce)); } /** @@ -135,7 +137,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); @@ -143,7 +147,7 @@ public final Either flatMap(Function invert() { - return flatMap(Either::right, Either::left); + return match(Either::right, Either::left); } /** @@ -201,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(); 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/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/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/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/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)) 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..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 @@ -43,6 +43,15 @@ default R into(BiFunction fn) { return fn.apply(_1(), _2()); } + /** + * Rotate the first two slots of this product. + * + * @return the rotated product + */ + 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/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/main/java/com/jnape/palatable/lambda/functions/Effect.java b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java index 62bfb941e..8a341d9a3 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Effect.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Effect.java @@ -5,23 +5,23 @@ import java.util.function.Consumer; 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.Fn0.fn0; +import static com.jnape.palatable.lambda.functions.IO.io; /** - * 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 { +public interface Effect extends Fn1>, Consumer { @Override - default void accept(A a) { - apply(a); + default IO apply(A a) { + return io(fn0(() -> accept(a))); } @Override @@ -46,9 +46,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/Fn0.java b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java index c3599b84f..84eb3e4a8 100644 --- a/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java +++ b/src/main/java/com/jnape/palatable/lambda/functions/Fn0.java @@ -4,10 +4,12 @@ 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; 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>. @@ -15,9 +17,12 @@ * @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(); /** * Invoke this function with {@link Unit}. @@ -26,55 +31,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,12 +82,17 @@ 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 default A get() { - return apply(UNIT); + return apply(); + } + + @Override + default A call() { + return apply(); } /** @@ -100,7 +103,7 @@ default A get() { * @return the {@link Fn0} */ static Fn0 fn0(Supplier supplier) { - return __ -> supplier.get(); + return supplier::get; } /** @@ -117,14 +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 unit -> { - fn.run(); - return unit; - }; + static Fn0 fn0(Runnable runnable) { + return io(runnable)::unsafePerformIO; } /** 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..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. @@ -36,7 +37,7 @@ public interface Fn1 extends Monad>, Profunctor, F * @return an {@link Fn0} */ default Fn0 thunk(A a) { - return __ -> apply(a); + return () -> apply(a); } /** @@ -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/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/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/Alter.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java new file mode 100644 index 000000000..f51050eae --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Alter.java @@ -0,0 +1,40 @@ +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.IO; + +import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; + +/** + * 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, IO> { + + private static final Alter INSTANCE = new Alter(); + + private Alter() { + } + + @Override + public IO apply(Effect effect, A a) { + return effect.fmap(io -> io.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 IO alter(Effect effect, A a) { + return Alter.alter(effect).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 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/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/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/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/semigroup/builtin/Intersection.java b/src/main/java/com/jnape/palatable/lambda/functions/builtin/fn2/Intersection.java similarity index 77% 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..178b7be8c 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,11 +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; import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly; import static com.jnape.palatable.lambda.functions.builtin.fn1.Distinct.distinct; @@ -19,7 +16,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(); @@ -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") 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/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/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/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/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/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/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/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) { } /** 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..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 @@ -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; + } } 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 new file mode 100644 index 000000000..0197295ee --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/functions/specialized/checked/CheckedEffect.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 CheckedEffect 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 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 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; + } } 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}. 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())); } /** 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..c6b4929c2 --- /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/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/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/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/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/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); } 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/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/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/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/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/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/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/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"); 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 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..4fe4837e0 --- /dev/null +++ b/src/test/java/com/jnape/palatable/lambda/adt/product/Product2Test.java @@ -0,0 +1,28 @@ +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; +import static org.junit.Assert.assertEquals; + +public class Product2Test { + + private Product2 product; + + @Before + public void setUp() { + product = product("a", "b"); + } + + @Test + public void staticFactoryMethod() { + assertEquals("a", product._1()); + assertEquals("b", product._2()); + } + + @Test + public void invert() { + 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 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/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)); + } } 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/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/AlterTest.java b/src/test/java/com/jnape/palatable/lambda/functions/builtin/fn2/AlterTest.java new file mode 100644 index 000000000..73e11e800 --- /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).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 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/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/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/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; 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/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)); + } +} 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 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 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/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; 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 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 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 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); + } +}